refactor: update session module references for consistency and clarity
ZhenYi committed
This change is very large, so some diffs are not shown. Clone the repository to see the full change.
Modified app/src/cli.rs app/src/cli.rs +1 −0 View app/src/cli.rs
@@ -10,6 +10,7 @@
1010#[derive(Subcommand)]
1111pub enum Command {
1212 Serve,
13 Mail,
1314 Migrate,
1415 IdentityOpenapi,
1516 Openapi {
Modified app/src/main.rs app/src/main.rs +119 −38 View app/src/main.rs
@@ -13,6 +13,7 @@
1313fn main() -> anyhow::Result<()> {
1414 match Cli::parse().command.unwrap_or(Command::Serve) {
1515 Command::Serve => serve(),
16 Command::Mail => mail(),
1617 Command::Migrate => migrate(),
1718 Command::Openapi { check } => openapi(check),
1819 Command::IdentityOpenapi => identity_openapi(),
@@ -48,25 +49,56 @@
4849 .await
4950 .context("connecting to the shared database")?,
5051 );
51 let auth_runtime = match auth_config()? {
52 let bind_addr = cfg.apihost.bind_addr().to_string();
53 let port = cfg.apihost.port();
54 let addr: SocketAddr = format!("{bind_addr}:{port}")
55 .parse()
56 .with_context(|| format!("parsing bind address {bind_addr}:{port}"))?;
57 let conn = queue::RocketMqConn::init(&cfg.rocketmq)
58 .await
59 .map_err(|err| anyhow::anyhow!("failed to start the rocketmq producer: {err}"))?;
60
61 let auth_config = auth_config()?;
62 let (auth_svc, client, mail, auth_events) = match auth_config.as_ref() {
5263 Some(auth_config) => {
5364 let db =
5465 auth::db::DbConn::new(database.primary().clone(), database.replicas().to_vec());
55 Some(
56 auth::runtime::start(&auth_config, db)
57 .await
58 .context("starting auth service")?,
66 let cache = auth::cache::Cache::connect(&app_config.redis)
67 .await
68 .context("connecting the auth cache")?;
69 let auth_events = auth::events::EventHandler::new(conn.clone());
70 let email_pool: config::email::EmailPoolConfig = auth_config
71 .section_or_default()
72 .context("loading email configuration")?;
73 let mail = auth::email::MailPublisher::new(
74 queue::Publisher::new(conn.clone()),
75 email_pool.mail_topic,
76 );
77 let pow: config::pow::PowConfig = auth_config
78 .section()
79 .context("loading pow configuration")?;
80 let service = auth::server::AuthSvc::new(
81 db,
82 cache,
83 Some(mail.clone()),
84 Some(auth_events.clone()),
85 auth_config
86 .section()
87 .context("loading auth configuration")?,
88 pow,
89 session_config.max_age.max(1) as u64,
5990 )
91 .await
92 .context("starting the auth service")?;
93 let client = std::sync::Arc::new(auth::client::KenAuthClient::local(
94 service.clone(),
95 2_000,
96 ));
97 (Some(service), Some(client), Some(mail), Some(auth_events))
6098 }
61 None => None,
99 None => (None, None, None, None),
62100 };
63 let client = auth_runtime.as_ref().map(|runtime| {
64 std::sync::Arc::new(auth::client::KenAuthClient::local(
65 runtime.service().clone(),
66 2_000,
67 ))
68 });
69 let state = export::AppState::with_identity(app_config, database, client)
101 let state = export::AppState::with_identity(app_config, database, client, mail)
70102 .await
71103 .context("building AppState")?;
72104 info!("dependencies ready");
@@ -85,12 +117,6 @@
85117 tokio::spawn(chat::worker::run_background_tasks(state.clone()));
86118 tokio::spawn(deletion::run_worker(state.clone()));
87119
88 let conn = queue::RocketMqConn::init(&cfg.rocketmq)
89 .await
90 .map_err(|err| anyhow::anyhow!("failed to start the rocketmq producer: {err}"))?;
91 let auth_events = auth_runtime
92 .as_ref()
93 .and_then(|runtime| runtime.service().events().cloned());
94120 let relay = events::outbox::OutboxRelay::start(
95121 auth_events,
96122 Some(queue::Publisher::new(conn.clone())),
@@ -111,16 +137,10 @@
111137 );
112138 }
113139
114 let verifier = webapi::verifier(&state);
115140 let doc = api_doc();
116141 let app_state = state.clone();
142 let auth_service = auth_svc.clone();
117143
118 let bind_addr = cfg.apihost.bind_addr().to_string();
119 let port = cfg.apihost.port();
120 let addr: SocketAddr = format!("{bind_addr}:{port}")
121 .parse()
122 .with_context(|| format!("parsing bind address {bind_addr}:{port}"))?;
123
124144 let server = HttpServer::new(move || {
125145 let state = app_state.clone();
126146 let mut app = App::new()
@@ -131,17 +151,19 @@
131151 .error_handler(export::http::json_error),
132152 )
133153 .app_data(web::PayloadConfig::new(webapi::MAX_REQUEST_BODY_BYTES));
134 if let Some(verifier) = verifier.clone() {
135 app = app.app_data(web::Data::new(verifier));
154 if let Some(service) = auth_service.clone() {
155 app = app.app_data(web::Data::new(service));
136156 }
137157 app.wrap(auth::session::SessionMiddleware::new(
138158 session_config.clone(),
139159 session_store.clone(),
140160 ))
161 .wrap(auth::envelope::EnvelopeContext)
141162 .wrap(webapi::build_cors(&state.config.web))
142163 .wrap(from_fn(export::middleware::trace_request))
143164 .wrap(from_fn(export::telemetry::http_telemetry))
144165 .wrap(from_fn(webapi::auth::session::revalidate::revalidate))
166 .wrap(from_fn(webapi::auth::session::csrf::csrf))
145167 .service(web::resource("/api/docs").route(web::get().to(|| async {
146168 actix_web::HttpResponse::Found()
147169 .insert_header((actix_web::http::header::LOCATION, "/api/docs/"))
@@ -149,6 +171,7 @@
149171 })))
150172 .service(SwaggerUi::new("/api/docs/{_:.*}").url("/api/docs/openapi.json", doc.clone()))
151173 .service(webapi::scope(state))
174 .default_service(web::to(auth::assets::serve))
152175 })
153176 .disable_signals()
154177 .bind(addr)
@@ -163,16 +186,30 @@
163186 handle.stop(true).await;
164187 });
165188 let api = async move { server.await.context("actix server error") };
166 let auth_cancel = cancel.clone();
167 let auth_server = async move {
168 match auth_runtime {
169 Some(runtime) => runtime.serve_until(auth_cancel).await,
170 None => {
171 auth_cancel.cancelled().await;
172 Ok(())
189
190 let grpc = if let Some(auth_config) = auth_config.as_ref() {
191 let server_config: config::server::ServerConfig = auth_config
192 .section()
193 .context("loading server configuration")?;
194 let listener = tokio::net::TcpListener::bind(server_config.grpc_addr)
195 .await
196 .with_context(|| format!("binding gRPC on {}", server_config.grpc_addr))?;
197 let grpc_cancel = cancel.clone();
198 let incoming = tokio_stream::wrappers::TcpListenerStream::new(listener);
199 Some(tokio::spawn(async move {
200 if let Err(error) = auth::server::grpc::router()
201 .serve_with_incoming_shutdown(tonic::service::Routes::default(), incoming, async move {
202 grpc_cancel.cancelled().await;
203 })
204 .await
205 {
206 warn!(%error, "gRPC server stopped");
173207 }
174 }
208 }))
209 } else {
210 None
175211 };
212
176213 let signal = async {
177214 tokio::select! {
178215 _ = export::telemetry::shutdown_signal() => cancel.cancel(),
@@ -183,13 +220,14 @@
183220 if let Err(error) = relay.shutdown().await {
184221 warn!(%error, "shutting down the event outbox relay failed");
185222 }
186 let auth_result = auth_server.await;
223 if let Some(grpc) = grpc {
224 let _ = grpc.await;
225 }
187226 for task in push_tasks {
188227 let _ = task.await;
189228 }
190229 conn.shutdown().await;
191230 api_result?;
192 auth_result?;
193231
194232 export::telemetry::shutdown_telemetry();
195233
@@ -198,6 +236,49 @@
198236}
199237
200238#[tokio::main]
239async fn mail() -> anyhow::Result<()> {
240 use tokio_util::sync::CancellationToken;
241
242 export::telemetry::init_tracing();
243
244 let figment = config::loader::figment().context("loading configuration")?;
245 let rocketmq: config::rocketmq::RocketMqConfig = figment
246 .extract_inner("rocketmq")
247 .context("loading rocketmq configuration")?;
248 let smtp: config::smtp::SmtpConfig = figment
249 .extract_inner("smtp")
250 .context("loading smtp configuration")?;
251 let email: config::email::EmailPoolConfig = figment
252 .extract_inner("email")
253 .context("loading email configuration")?;
254 rocketmq.is_valid().map_err(anyhow::Error::msg)?;
255 smtp.is_valid().map_err(anyhow::Error::msg)?;
256 email.is_valid().map_err(anyhow::Error::msg)?;
257
258 let conn = queue::RocketMqConn::init(&rocketmq)
259 .await
260 .map_err(|err| anyhow!("failed to start the rocketmq producer: {err}"))?;
261 let events = auth::events::EventHandler::new(conn.clone());
262 let consumer = auth::email::EmailConsumer::new(smtp, email, Some(events))
263 .context("building the mail consumer")?;
264
265 let cancel = CancellationToken::new();
266 let run_cancel = cancel.clone();
267 let run = consumer.run(rocketmq, run_cancel);
268 let signal = async {
269 tokio::select! {
270 _ = export::telemetry::shutdown_signal() => cancel.cancel(),
271 _ = cancel.cancelled() => {},
272 }
273 };
274 let (result, ()) = tokio::join!(run, signal);
275 conn.shutdown().await;
276 result.context("mail service failed")?;
277 export::telemetry::shutdown_telemetry();
278 Ok(())
279}
280
281#[tokio::main]
201282async fn migrate() -> anyhow::Result<()> {
202283 use config::scoped::{MigrateConfig, ScopedConfig};
203284 use models::migrate::sync_schema;
Modified app/Cargo.toml app/Cargo.toml +3 −1 View app/Cargo.toml
@@ -15,7 +15,7 @@
1515deletion = { workspace = true }
1616events = { workspace = true }
1717export = { workspace = true }
18token = { workspace = true }
18session = { workspace = true }
1919models = { workspace = true }
2020push = { workspace = true }
2121queue = { workspace = true }
@@ -29,3 +29,5 @@
2929webapi = { workspace = true }
3030
3131utoipa-identity = { package = "utoipa", version = "6.0.0" }
32tokio-stream = { version = "0.1", features = ["net"] }
33tonic = { workspace = true }
Modified charts/core/values.yaml charts/core/values.yaml +0 −2 View charts/core/values.yaml
@@ -40,8 +40,6 @@
4040 APP_ROCKETMQ__NAME_SERVER: "rocketmq-namesrv:9876"
4141 APP_ROCKETMQ__TOPIC_PREFIX: "gitdata"
4242 # 认证中心:浏览器走同域 session,服务间走 gRPC(x-rpc-key)。
43 APP_JWT__ISSUER: "https://auth.gitdata.ai"
44 APP_JWT__SESSION_COOKIE: "gitdata_session"
4543 RUST_LOG: "info"
4644
4745# 敏感配置(渲染为 Secret)。注意 AppConfig 的 Debug 会带出密钥,
Modified charts/prod/values/prod.yaml charts/prod/values/prod.yaml +1 −1 View charts/prod/values/prod.yaml
@@ -23,7 +23,7 @@
2323 APP_PUSH__VAPID_SUBJECT: "mailto:bot@mail.gitdata.ai"
2424 APP_WEB__WEB_BASE_URL: "https://gitdata.ai"
2525 APP_WEB__CORS_ALLOW_ORIGINS: '["https://gitdata.ai"]'
26 APP_JWT__COOKIE_SECURE: "true"
26 APP_SESSION__SECURE: "true"
2727 APP_GIT__BASE_URL: "https://gitdata.ai"
2828 APP_LIVEKIT__RECORDING_ENABLED: "false"
2929 RUST_LOG: "info"
Modified config/default/auth.json config/default/auth.json +1 −4 View config/default/auth.json
@@ -29,8 +29,5 @@
2929 "content_md": "Placeholder privacy policy."
3030 }
3131 ],
32 "rpc_key": "REPLACE_WITH_RPC_KEY_AT_LEAST_32_CHARS",
33 "socket_origins": [
34 "https://gitdata.ai"
35 ]
32 "rpc_key": "REPLACE_WITH_RPC_KEY_AT_LEAST_32_CHARS"
3633}
Modified config/default/email.json config/default/email.json +4 −1 View config/default/email.json
@@ -4,5 +4,8 @@
44 "capacity": 1024,
55 "enqueue_timeout_ms": 5000,
66 "retry_delay_ms": 2000,
7 "max_attempts": 3
7 "max_attempts": 3,
8 "mail_topic": "gitdata-mail",
9 "consumer_group": "gitdata-mail",
10 "max_reconsume": 5
811}
Modified config/default/server.json config/default/server.json +1 −2 View config/default/server.json
@@ -1,4 +1,3 @@
11{
2 "http_addr": "127.0.0.1:7021",
32 "grpc_addr": "127.0.0.1:7022"
4}
3}
No newline at end of file
Modified config/default/session.json config/default/session.json +3 −2 View config/default/session.json
@@ -1,9 +1,10 @@
11{
22 "cookie_name": "session",
33 "max_age": 2592000,
4 "anonymous_max_age": 300,
4 "anonymous_max_age": 3600,
55 "path": "/",
66 "secure": false,
77 "same_site": "Lax",
8 "trust_proxy": false
8 "trust_proxy": false,
9 "recheck_secs": 60
910}
Modified deploy/compose.yaml deploy/compose.yaml +1 −1 View deploy/compose.yaml
@@ -3,7 +3,7 @@
33# docker compose up -d # 用已有镜像启动
44# docker compose up -d --build # 从仓库根目录 Dockerfile 重新构建
55#
6# 端口:7051 = API;7021 = identity HTTP/登录页;7022 = 兼容外部服务的认证 gRPC。
6# 端口:7051 = API(含认证 HTTP/登录页);7022 = 认证 gRPC(当前为空路由,按需加回)。
77# config 里另留了 7052(githost HTTP)与 7053(git SSH)两个口,但当前 apihost
88# 二进制不监听它们(git 读写走 KenShell),改由 KenShell 的 7011/7012 承担。
99#
Modified lib/auth/src/client/local/mod.rs lib/auth/src/client/local/mod.rs +0 −6 View lib/auth/src/client/local/mod.rs
@@ -1,23 +1,17 @@
1mod access_key;
21mod agreement;
32mod authority;
43mod authorization;
5mod email;
64mod identity;
75mod mfa;
86mod organization;
97mod session;
108mod ssh_key;
11mod token;
129
13pub use access_key::AccessKeyClient;
1410pub use agreement::AgreementClient;
1511pub use authority::AuthorityClient;
1612pub use authorization::AuthorizationClient;
17pub use email::EmailClient;
1813pub use identity::IdentityClient;
1914pub use mfa::MfaClient;
2015pub use organization::OrganizationClient;
2116pub use session::SessionClient;
2217pub use ssh_key::SshKeyClient;
23pub use token::TokenClient;
Modified lib/auth/src/client/client.rs lib/auth/src/client/client.rs +0 −192 View lib/auth/src/client/client.rs
@@ -1,9 +1,7 @@
1use std::collections::HashMap;
21use std::time::Duration;
32
43use crate::server::AuthSvc;
54use tonic::Request;
6use uuid::Uuid;
75
86use crate::client::error::KenAuthError;
97use crate::protos::auth as proto;
@@ -44,10 +42,6 @@
4442 crate::client::local::AuthorityClient::new(self.service.clone())
4543 }
4644
47 pub fn email(&self) -> crate::client::local::EmailClient {
48 crate::client::local::EmailClient::new(self.service.clone())
49 }
50
5145 pub fn session(&self) -> crate::client::local::SessionClient {
5246 crate::client::local::SessionClient::new(self.service.clone())
5347 }
@@ -56,18 +50,10 @@
5650 crate::client::local::OrganizationClient::new(self.service.clone())
5751 }
5852
59 pub fn token(&self) -> crate::client::local::TokenClient {
60 crate::client::local::TokenClient::new(self.service.clone())
61 }
62
6353 pub fn authorization(&self) -> crate::client::local::AuthorizationClient {
6454 crate::client::local::AuthorizationClient::new(self.service.clone())
6555 }
6656
67 pub fn access_key(&self) -> crate::client::local::AccessKeyClient {
68 crate::client::local::AccessKeyClient::new(self.service.clone())
69 }
70
7157 pub fn ssh_key(&self) -> crate::client::local::SshKeyClient {
7258 crate::client::local::SshKeyClient::new(self.service.clone())
7359 }
@@ -191,84 +177,7 @@
191177 .map(|response| response.into_inner())
192178 }
193179
194 pub async fn list_access_keys(
195 &self,
196 user_id: i64,
197 include_revoked: bool,
198 page: proto::common::v1::PageRequest,
199 ) -> Result<proto::v1::ListAccessKeysResponse, KenAuthError> {
200 let mut client = self.access_key();
201 client
202 .list_access_keys(self.read_request(proto::v1::ListAccessKeysRequest {
203 user_id,
204 include_revoked,
205 page: Some(page),
206 }))
207 .await
208 .map_err(KenAuthError::from_status)
209 .map(|response| response.into_inner())
210 }
211
212180 #[allow(clippy::too_many_arguments)]
213 pub async fn create_access_key(
214 &self,
215 user_id: i64,
216 name: &str,
217 description: &str,
218 scopes: Vec<i32>,
219 expires_in_secs: i64,
220 client_ip: &str,
221 ) -> Result<proto::v1::CreateAccessKeyResponse, KenAuthError> {
222 let mut client = self.access_key();
223 client
224 .create_access_key(self.write_request(proto::v1::CreateAccessKeyRequest {
225 user_id,
226 name: name.to_string(),
227 description: description.to_string(),
228 scopes,
229 expires_in_secs,
230 client_ip: client_ip.to_string(),
231 }))
232 .await
233 .map_err(KenAuthError::from_status)
234 .map(|response| response.into_inner())
235 }
236
237 pub async fn rotate_access_key(
238 &self,
239 user_id: i64,
240 access_key_id: &str,
241 client_ip: &str,
242 ) -> Result<proto::v1::RotateAccessKeyResponse, KenAuthError> {
243 let mut client = self.access_key();
244 client
245 .rotate_access_key(self.write_request(proto::v1::RotateAccessKeyRequest {
246 user_id,
247 access_key_id: access_key_id.to_string(),
248 client_ip: client_ip.to_string(),
249 }))
250 .await
251 .map_err(KenAuthError::from_status)
252 .map(|response| response.into_inner())
253 }
254
255 pub async fn revoke_access_key(
256 &self,
257 user_id: i64,
258 access_key_id: &str,
259 reason: &str,
260 ) -> Result<proto::v1::RevokeAccessKeyResponse, KenAuthError> {
261 let mut client = self.access_key();
262 client
263 .revoke_access_key(self.write_request(proto::v1::RevokeAccessKeyRequest {
264 user_id,
265 access_key_id: access_key_id.to_string(),
266 reason: reason.to_string(),
267 }))
268 .await
269 .map_err(KenAuthError::from_status)
270 .map(|response| response.into_inner())
271 }
272181
273182 pub async fn list_user_ssh_keys(
274183 &self,
@@ -382,42 +291,6 @@
382291 request
383292 }
384293
385 /// Enqueue one plain text / HTML mail on `kenoauth`.
386 ///
387 /// `kenoauth` owns SMTP, retries and backpressure; a `Ok` here means the
388 /// message was accepted into its queue, while delivery outcome is visible
389 /// through `GetQueueStatus` / the delivery events on that side.
390 pub async fn send_mail(
391 &self,
392 to: &str,
393 subject: &str,
394 text: &str,
395 html: &str,
396 ) -> Result<(), KenAuthError> {
397 let mut client = self.email();
398 let request = proto::internal::v1::SendEmailRequest {
399 request_id: Uuid::now_v7().to_string(),
400 to: vec![proto::internal::v1::EmailAddress {
401 address: to.to_string(),
402 name: String::new(),
403 }],
404 cc: Vec::new(),
405 bcc: Vec::new(),
406 subject: subject.to_string(),
407 text: text.to_string(),
408 html: html.to_string(),
409 reply_to: None,
410 attachments: Vec::new(),
411 metadata: HashMap::new(),
412 trace_id: String::new(),
413 };
414 client
415 .send_email(self.write_request(request))
416 .await
417 .map_err(KenAuthError::from_status)?;
418 Ok(())
419 }
420
421294 pub async fn get_session(
422295 &self,
423296 user_id: i64,
@@ -606,71 +479,6 @@
606479 .await
607480 .map_err(KenAuthError::from_status)?;
608481 Ok(())
609 }
610
611 pub async fn verify_access_key(
612 &self,
613 token: &str,
614 required_scopes: Vec<i32>,
615 ) -> Result<Option<proto::common::v1::Principal>, KenAuthError> {
616 let mut client = self.access_key();
617 let response = client
618 .verify_access_key(self.read_request(proto::v1::VerifyAccessKeyRequest {
619 access_key: token.to_string(),
620 required_scopes,
621 client_ip: String::new(),
622 }))
623 .await
624 .map_err(KenAuthError::from_status)?
625 .into_inner();
626 if !response.valid {
627 return Ok(None);
628 }
629 Ok(response.principal)
630 }
631
632 pub async fn issue_service_token(
633 &self,
634 user_id: i64,
635 audience: i32,
636 scopes: Vec<i32>,
637 ttl_seconds: u32,
638 event_id: &str,
639 ) -> Result<proto::v1::IssueServiceTokenResponse, KenAuthError> {
640 let mut client = self.token();
641 client
642 .issue_service_token(self.write_request(proto::v1::IssueServiceTokenRequest {
643 audience,
644 subject_user_id: user_id,
645 scopes,
646 ttl_seconds,
647 constraint: None,
648 event_id: event_id.to_string(),
649 }))
650 .await
651 .map_err(KenAuthError::from_status)
652 .map(|response| response.into_inner())
653 }
654
655 pub async fn introspect_token(
656 &self,
657 token: &str,
658 ) -> Result<proto::v1::IntrospectTokenResponse, KenAuthError> {
659 let mut client = self.token();
660 let credential = Some(proto::common::v1::Credential {
661 kind: Some(proto::common::v1::credential::Kind::ServiceToken(
662 token.to_string(),
663 )),
664 request_id: String::new(),
665 });
666 client
667 .introspect_token(self.read_request(proto::v1::IntrospectTokenRequest {
668 credential,
669 required_scopes: Vec::new(),
670 }))
671 .await
672 .map_err(KenAuthError::from_status)
673 .map(|response| response.into_inner())
674482 }
675483
676484 pub async fn lookup_ssh_key(
Modified lib/auth/src/server/grpc/authority.rs lib/auth/src/server/grpc/authority.rs +38 −91 View lib/auth/src/server/grpc/authority.rs
@@ -1,5 +1,3 @@
1use crate::jwt::JwtError;
2use crate::jwt::authority::{AccessRecord, Authority, UserRecord};
31use crate::models::users::users;
42use crate::protos::auth::common::v1::{Code, PageResponse};
53use crate::protos::auth::internal::v1::authority_service_server::{
@@ -16,6 +14,7 @@
1614use tonic::{Request, Response, Status};
1715
1816use crate::server::AuthSvc;
17use crate::server::errors::AuthError;
1918use crate::server::grpc::{context, convert, error, store};
2019
2120pub struct AuthorityApi {
@@ -38,48 +37,45 @@
3837 }
3938}
4039
41/// 把 jwt 侧的失败翻译成 gRPC 状态。调用方(crate::jwt::authority::GrpcAuthority)会把
42/// 除 UNKNOWN/INTERNAL/UNAVAILABLE 之外的一切折叠回 `JwtError::Revoked`,所以
43/// 这里选择的具体码只影响可观测性,不影响业务分支。
44fn status(error_value: &JwtError, request_id: Option<&str>) -> Status {
40fn status(error_value: &AuthError, request_id: Option<&str>) -> Status {
4541 let code = match error_value {
46 JwtError::Revoked => Code::TokenRevoked,
47 JwtError::Missing | JwtError::Redirect(_) => Code::Unauthenticated,
48 JwtError::Malformed => Code::MalformedRequest,
49 JwtError::UnknownKey | JwtError::UnsupportedKey | JwtError::BadSignature => {
50 Code::InvalidAccessToken
42 AuthError::Unauthenticated | AuthError::SecurityVersionStale { .. } => {
43 Code::Unauthenticated
5144 }
52 JwtError::Expired => Code::TokenExpired,
53 JwtError::BadIssuer | JwtError::WrongAudience => Code::InvalidAccessToken,
54 JwtError::Config(_) | JwtError::Internal(_) => Code::Internal,
45 AuthError::Forbidden => Code::Forbidden,
46 AuthError::UserNotFound => Code::UserNotFound,
47 AuthError::SessionNotFound => Code::SessionNotFound,
48 AuthError::MalformedRequest => Code::MalformedRequest,
49 AuthError::VersionMismatch { .. } => Code::Conflict,
5550 _ => Code::Internal,
5651 };
5752 error::status_of(code, error_value.message(), request_id)
5853}
5954
60/// 账号读取的失败语义比令牌校验更窄:只有"查不到"这一种正常失败。
61fn user_status(error_value: &JwtError, request_id: Option<&str>) -> Status {
55fn user_status(error_value: &AuthError, request_id: Option<&str>) -> Status {
6256 match error_value {
63 JwtError::Revoked => error::status_of(Code::UserNotFound, "user not found", request_id),
57 AuthError::UserNotFound => {
58 error::status_of(Code::UserNotFound, "user not found", request_id)
59 }
6460 other => status(other, request_id),
6561 }
6662}
6763
68fn access(record: &AccessRecord) -> AuthorityAccess {
64fn access(user: &users::Model, mfa_verified: bool) -> AuthorityAccess {
6965 AuthorityAccess {
70 id: record.id,
71 username: record.username.clone(),
72 allow_use: record.allow_use,
73 forbid_login: record.forbid_login,
74 endtime_forbid_login_at: convert::datetime_opt(record.endtime_forbid_login_at),
75 is_admin: record.is_admin,
76 security_version: record.security_version,
77 deleted_at: convert::datetime_opt(record.deleted_at),
78 mfa_verified: record.mfa_verified,
66 id: user.id,
67 username: user.username.clone(),
68 allow_use: user.allow_use,
69 forbid_login: user.forbid_login,
70 endtime_forbid_login_at: convert::datetime_opt(user.endtime_forbid_login_at),
71 is_admin: user.is_admin,
72 security_version: user.security_version,
73 deleted_at: convert::datetime_opt(user.deleted_at),
74 mfa_verified,
7975 }
8076}
8177
82fn user(record: &UserRecord) -> AuthorityUser {
78fn user(record: &users::Model) -> AuthorityUser {
8379 AuthorityUser {
8480 id: record.id,
8581 username: record.username.clone(),
@@ -269,70 +265,25 @@
269265}
270266
271267impl AuthorityApi {
272 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
268 #[tracing::instrument(skip_all, fields(request_id = %_request_id.unwrap_or_default()))]
273269 async fn redeem_socket_ticket_inner(
274270 &self,
275 request_id: Option<&str>,
276 payload: crate::protos::auth::internal::v1::RedeemSocketTicketRequest,
271 _request_id: Option<&str>,
272 _payload: crate::protos::auth::internal::v1::RedeemSocketTicketRequest,
277273 ) -> Result<Response<crate::protos::auth::internal::v1::RedeemSocketTicketResponse>, Status>
278274 {
279 let grant = self
280 .svc
281 .redeem_socket_ticket(&payload.ticket, &payload.origin, request_id)
282 .await
283 .map_err(|failure| error::status(&failure, request_id))?;
284 Ok(Response::new(
285 crate::protos::auth::internal::v1::RedeemSocketTicketResponse {
286 user_id: grant.user_id,
287 security_version: grant.version,
288 session_id: grant.session_id,
289 scopes_bounded: grant.scopes.is_some(),
290 scopes: grant.scopes.unwrap_or_default(),
291 credential_expires_at: grant.credential_expires_at.unwrap_or_default(),
292 },
293 ))
275 Err(Status::unimplemented("socket tickets are not available"))
294276 }
295277
296 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
278 #[tracing::instrument(skip_all, fields(request_id = %_request_id.unwrap_or_default()))]
297279 async fn validate_inner(
298280 &self,
299 request_id: Option<&str>,
300 payload: ValidateRequest,
281 _request_id: Option<&str>,
282 _payload: ValidateRequest,
301283 ) -> Result<Response<ValidateResponse>, Status> {
302 let token = payload.token;
303 if token.is_empty() {
304 return Err(status(&JwtError::Missing, request_id));
305 }
306 let claims = std::iter::once(crate::jwt::PLATFORM_AUDIENCE)
307 .chain(
308 self.svc
309 .apps()
310 .apps()
311 .iter()
312 .map(|app| app.audience_or_id()),
313 )
314 .find_map(|audience| crate::jwt::verify_for_audience(&token, audience).ok())
315 .ok_or_else(|| status(&JwtError::WrongAudience, request_id))?;
316 if claims.token_type != "access" {
317 return Err(error::invalid_argument(
318 "token type is not access",
319 request_id,
320 ));
321 }
322 let record = self
323 .svc
324 .validate(&token, &claims)
325 .await
326 .map_err(|error_value| status(&error_value, request_id))?;
327 tracing::debug!(
328 request_id,
329 user_id = record.id,
330 session = claims.session_id.is_some(),
331 "authority validated an access token"
332 );
333 Ok(Response::new(ValidateResponse {
334 access: Some(access(&record)),
335 }))
284 Err(Status::unimplemented(
285 "access token validation is not available",
286 ))
336287 }
337288
338289 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
@@ -408,7 +359,7 @@
408359 request_id,
409360 ));
410361 }
411 let record = self
362 let (user, mfa_verified) = self
412363 .svc
413364 .check_session(
414365 payload.user_id,
@@ -424,7 +375,7 @@
424375 "authority revalidated a session"
425376 );
426377 Ok(Response::new(GetSessionResponse {
427 access: Some(access(&record)),
378 access: Some(access(&user, mfa_verified)),
428379 }))
429380 }
430381
@@ -455,8 +406,7 @@
455406 let record =
456407 self.svc.update(payload.user_id, value).await.map_err(
457408 |error_value| match error_value {
458 // 结构校验已在上面完成,update 里剩下的 Malformed 只可能是版本 CAS 落空。
459 JwtError::Malformed => {
409 AuthError::VersionMismatch { .. } => {
460410 error::status_of(Code::Conflict, "account version conflict", request_id)
461411 }
462412 other => status(&other, request_id),
@@ -510,10 +460,7 @@
510460 String::new()
511461 };
512462 Ok(Response::new(ListUsersResponse {
513 users: rows
514 .iter()
515 .map(|row| user(&crate::server::authority::record(row.clone())))
516 .collect(),
463 users: rows.iter().map(user).collect(),
517464 page: Some(PageResponse { next_page_token }),
518465 }))
519466 }
Modified lib/auth/src/server/grpc/authorization.rs lib/auth/src/server/grpc/authorization.rs +1 −1 View lib/auth/src/server/grpc/authorization.rs
@@ -12,8 +12,8 @@
1212
1313use crate::server::AuthSvc;
1414use crate::server::errors::{AuthError, AuthResult};
15use crate::server::grpc::store::ALLOWED_APP_SCOPES;
1516use crate::server::grpc::{agreement, context, error, store};
16use crate::server::http::access_token::types::ALLOWED_APP_SCOPES;
1717
1818const MAX_BATCH_CAPABILITIES: usize = 32;
1919const ADMIN_CACHE_TTL_SECS: u64 = 300;
Modified lib/auth/src/server/grpc/cache_maintenance.rs lib/auth/src/server/grpc/cache_maintenance.rs +1 −2 View lib/auth/src/server/grpc/cache_maintenance.rs
@@ -203,8 +203,7 @@
203203 Ok(user) if user.deleted_at.is_none() => user,
204204 _ => return (user_id, false),
205205 };
206 let mut me = MeResponse::from(user);
207 me.avatar_url = svc.avatar_url(user_id).await.ok().flatten();
206 let me = MeResponse::from(user);
208207 match svc
209208 .cache()
210209 .set_json_ex(
Modified lib/auth/src/server/grpc/convert.rs lib/auth/src/server/grpc/convert.rs +2 −17 View lib/auth/src/server/grpc/convert.rs
@@ -1,5 +1,5 @@
1use crate::models::users::{user_access_tokens, user_sessions, user_ssh_keys};
2use crate::protos::auth::common::v1::{AccessKeyInfo, SessionInfo, SshKeyInfo};
1use crate::models::users::{user_sessions, user_ssh_keys};
2use crate::protos::auth::common::v1::{SessionInfo, SshKeyInfo};
33use chrono::{DateTime, NaiveDate, TimeZone, Utc};
44use prost_types::Timestamp;
55
@@ -56,21 +56,6 @@
5656 mfa_verified_at: datetime_opt(row.mfa_verified_at),
5757 revoked_at: datetime_opt(row.revoked_at),
5858 revoke_reason: String::new(),
59 }
60}
61
62pub fn access_key_info(row: &user_access_tokens::Model) -> AccessKeyInfo {
63 AccessKeyInfo {
64 access_key_id: row.id.to_string(),
65 name: row.name.clone(),
66 description: row.description.clone().unwrap_or_default(),
67 fingerprint: row.fingerprint.clone().unwrap_or_default(),
68 scopes: store::scope_codes(&store::scopes_from_names(&row.scope)),
69 hash_key_id: row.hash_key_id.clone(),
70 created_at: datetime_opt(Some(row.created_at)),
71 expires_at: datetime_opt(row.expires_at),
72 last_used_at: datetime_opt(row.last_used_at),
73 revoked_at: datetime_opt(row.revoked_at),
7459 }
7560}
7661
Modified lib/auth/src/server/grpc/identity.rs lib/auth/src/server/grpc/identity.rs +22 −333 View lib/auth/src/server/grpc/identity.rs
@@ -1,10 +1,6 @@
1use crate::models::users::{user_ssh_keys, users};
2use crate::protos::auth::common::v1::{
3 AuthMethod, Code, Credential, Principal, TokenScope, credential,
4};
1use crate::models::users::users;
52use crate::protos::auth::v1::identity_service_server::{IdentityService, IdentityServiceServer};
63use crate::protos::auth::v1::*;
7use crate::session::Session;
84use chrono::Utc;
95use rand::RngExt as _;
106use sea_orm::sea_query::{Expr, ExprTrait};
@@ -13,59 +9,13 @@
139
1410use crate::server::AuthSvc;
1511use crate::server::errors::{AuthError, AuthResult};
16use crate::server::grpc::{context, convert, error, service_token, store};
17use crate::server::http::access_token::types::AccessTokenAuthRequest;
18use crate::server::http::ssh_key::service;
19
20fn ensure_authorized(
21 principal: &Principal,
22 required_scopes: &[i32],
23 require_mfa: bool,
24 scopes_bounded: bool,
25) -> AuthResult<()> {
26 if !required_scopes.is_empty()
27 && scopes_bounded
28 && !store::scopes_cover(&principal.scopes, required_scopes)
29 {
30 let missing = required_scopes
31 .iter()
32 .copied()
33 .find(|required| *required != 0 && !principal.scopes.contains(required))
34 .and_then(|required| TokenScope::try_from(required).ok())
35 .and_then(store::scope_name)
36 .unwrap_or_default();
37 return Err(AuthError::ScopeInsufficient {
38 required: missing.to_owned(),
39 });
40 }
41 if require_mfa && !principal.mfa_verified {
42 return Err(AuthError::MfaRequired);
43 }
44 Ok(())
45}
12use crate::server::grpc::{context, error, store};
4613
4714#[derive(Clone)]
4815pub struct IdentityApi {
4916 svc: AuthSvc,
5017}
5118
52fn credential_ref(credential: Option<&Credential>) -> AuthResult<(&'static str, &str)> {
53 let kind = credential
54 .and_then(|value| value.kind.as_ref())
55 .ok_or(AuthError::MalformedRequest)?;
56 let (label, raw) = match kind {
57 credential::Kind::SessionKey(raw) => ("session", raw.as_str()),
58 credential::Kind::AccessToken(raw) => ("access_token", raw.as_str()),
59 credential::Kind::ServiceToken(raw) => ("service_token", raw.as_str()),
60 credential::Kind::SshFingerprint(raw) => ("ssh", raw.as_str()),
61 credential::Kind::SshPublicKey(raw) => ("ssh", raw.as_str()),
62 };
63 if raw.trim().is_empty() {
64 return Err(AuthError::MalformedRequest);
65 }
66 Ok((label, raw))
67}
68
6919impl IdentityApi {
7020 pub fn new(svc: AuthSvc) -> Self {
7121 Self { svc }
@@ -80,194 +30,6 @@
8030 let gate = context::Interceptor::new(self.svc.auth().rpc_key.clone());
8131 IdentityServiceServer::with_interceptor(self, gate)
8232 }
83
84 async fn ssh_user(&self, fingerprint: &str) -> AuthResult<users::Model> {
85 let record = user_ssh_keys::Entity::find()
86 .filter(user_ssh_keys::Column::Fingerprint.eq(fingerprint.trim()))
87 .one(self.svc.db().read())
88 .await?
89 .ok_or(AuthError::Unauthenticated)?;
90 if record.revoked_at.is_some()
91 || record
92 .expires_at
93 .is_some_and(|expires| expires <= Utc::now())
94 {
95 return Err(AuthError::Unauthenticated);
96 }
97 store::load_active_user(self.svc.db(), record.user_id).await
98 }
99
100 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
101 async fn principal_of(
102 &self,
103 request_id: Option<&str>,
104 inner: &AuthenticateRequest,
105 ) -> AuthResult<AuthenticateResponse> {
106 // 仅作入参校验(空凭据在此拒绝);原 principal 缓存键已随写缓存一并移除。
107 let _ = credential_ref(inner.credential.as_ref())?;
108
109 let credential = inner
110 .credential
111 .as_ref()
112 .and_then(|value| value.kind.as_ref())
113 .ok_or(AuthError::MalformedRequest)?;
114 let expected_audience =
115 (!inner.expected_audience.is_empty()).then_some(inner.expected_audience.as_str());
116 let (method, user, session_id, access_key_id, granted, mfa_verified, service_id) =
117 match credential {
118 credential::Kind::SessionKey(key) => {
119 let Some(state) = store::load_session(self.svc.cache(), key).await? else {
120 return Err(AuthError::Unauthenticated);
121 };
122 let (user_id, version, session_id) = {
123 let session = Session::from_state(state);
124 (
125 session.user_id()?.ok_or(AuthError::Unauthenticated)?,
126 session
127 .security_version()?
128 .ok_or(AuthError::Unauthenticated)?,
129 session
130 .get::<String>("auth_session_id")?
131 .ok_or(AuthError::Unauthenticated)?,
132 )
133 };
134 let active = self
135 .svc
136 .check_session(user_id, version, &session_id, request_id)
137 .await
138 .map_err(|_| AuthError::Unauthenticated)?;
139 let _ = store::index_session_key(
140 self.svc.cache(),
141 user_id,
142 key,
143 std::time::Duration::from_secs(self.svc.session_max_age_secs()),
144 )
145 .await;
146 let user = store::load_active_user(self.svc.db(), user_id).await?;
147 (
148 AuthMethod::Session,
149 user,
150 session_id,
151 String::new(),
152 None,
153 active.mfa_verified,
154 String::new(),
155 )
156 }
157 credential::Kind::AccessToken(token) => {
158 if token.matches('.').count() == 2 {
159 let claims = self
160 .svc
161 .authenticate_jwt_access_token(token, expected_audience)
162 .await?;
163 let user = store::load_active_user(self.svc.db(), claims.user_id).await?;
164 let scopes = claims.scope.as_deref().map(store::required_scope_codes);
165 (
166 AuthMethod::AccessToken,
167 user,
168 claims.session_id.clone().unwrap_or_default(),
169 String::new(),
170 scopes,
171 claims.mfa_verified,
172 String::new(),
173 )
174 } else {
175 let response = self
176 .svc
177 .authenticate_access_token(
178 AccessTokenAuthRequest {
179 token: token.clone(),
180 },
181 request_id.unwrap_or_default().to_owned(),
182 )
183 .await?;
184 let user = store::load_active_user(self.svc.db(), response.user_id).await?;
185 (
186 AuthMethod::AccessToken,
187 user,
188 String::new(),
189 response.token_id.to_string(),
190 Some(store::required_scope_codes(&response.scope)),
191 false,
192 String::new(),
193 )
194 }
195 }
196 credential::Kind::ServiceToken(token) => {
197 let claims = service_token::verify(
198 &self.svc.jwt().jwks(),
199 token,
200 &service_token::ALL_AUDIENCES,
201 )?;
202 if self
203 .svc
204 .cache()
205 .exists(&format!("auth:svc-token:revoked:{}", claims.token_id))
206 .await?
207 {
208 return Err(AuthError::Unauthenticated);
209 }
210 let user = store::load_active_user(self.svc.db(), claims.user_id).await?;
211 store::ensure_security_version(&user, claims.security_version)?;
212 (
213 AuthMethod::ServiceToken,
214 user,
215 String::new(),
216 String::new(),
217 Some(claims.scopes.clone()),
218 false,
219 claims.service_id.clone(),
220 )
221 }
222 credential::Kind::SshPublicKey(raw) => {
223 let (_, fingerprint) = service::parse_public_key(raw)?;
224 let user = self.ssh_user(&fingerprint).await?;
225 (
226 AuthMethod::SshKey,
227 user,
228 String::new(),
229 String::new(),
230 None,
231 false,
232 String::new(),
233 )
234 }
235 credential::Kind::SshFingerprint(fingerprint) => {
236 let user = self.ssh_user(fingerprint).await?;
237 (
238 AuthMethod::SshKey,
239 user,
240 String::new(),
241 String::new(),
242 None,
243 false,
244 String::new(),
245 )
246 }
247 };
248
249 store::ensure_security_version(&user, inner.min_security_version)?;
250 let scope_bounded = granted.is_some();
251 let mut principal = store::principal(&user, method);
252 principal.session_id = session_id;
253 principal.access_key_id = access_key_id;
254 principal.scopes = granted.unwrap_or_default();
255 principal.scopes_bounded = scope_bounded;
256 principal.mfa_verified = mfa_verified;
257 principal.service_id = service_id;
258 principal.authenticated_at = Some(convert::now_timestamp());
259 ensure_authorized(
260 &principal,
261 &inner.required_scopes,
262 inner.require_mfa,
263 scope_bounded,
264 )?;
265 let response = AuthenticateResponse {
266 principal: Some(principal),
267 cached: false,
268 };
269 Ok(response)
270 }
27133}
27234
27335fn random_bot_id() -> i64 {
@@ -374,6 +136,19 @@
374136 .await?;
375137
376138 let security_version = store::load_user(db, user.id).await?.security_version;
139 if let Some(keep) = keep {
140 if let Err(err) = store::refresh_session_version(
141 self.svc.cache(),
142 user.id,
143 keep,
144 security_version,
145 self.svc.session_max_age_secs(),
146 )
147 .await
148 {
149 tracing::warn!(%err, user_id = user.id, "failed to refresh the kept session version");
150 }
151 }
377152 Ok(ChangePasswordResponse {
378153 changed: true,
379154 security_version,
@@ -386,28 +161,16 @@
386161impl IdentityService for IdentityApi {
387162 async fn authenticate(
388163 &self,
389 request: Request<AuthenticateRequest>,
164 _request: Request<AuthenticateRequest>,
390165 ) -> Result<Response<AuthenticateResponse>, Status> {
391 let meta = context::meta(&request).await?;
392 let timer = crate::oltp::metrics::ActiveRpcGuard::new("auth.v1.IdentityService");
393 let result = self
394 .authenticate_inner(meta.request_id(), request.into_inner())
395 .await;
396 timer.finish("Authenticate", &result);
397 result
166 Err(Status::unimplemented("authenticate is not available"))
398167 }
399168
400169 async fn verify_credential(
401170 &self,
402 request: Request<VerifyCredentialRequest>,
171 _request: Request<VerifyCredentialRequest>,
403172 ) -> Result<Response<VerifyCredentialResponse>, Status> {
404 let meta = context::meta(&request).await?;
405 let timer = crate::oltp::metrics::ActiveRpcGuard::new("auth.v1.IdentityService");
406 let result = self
407 .verify_credential_inner(meta.request_id(), request.into_inner())
408 .await;
409 timer.finish("VerifyCredential", &result);
410 result
173 Err(Status::unimplemented("verify_credential is not available"))
411174 }
412175
413176 async fn get_user_public(
@@ -478,69 +241,6 @@
478241
479242impl IdentityApi {
480243 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
481 async fn authenticate_inner(
482 &self,
483 request_id: Option<&str>,
484 payload: AuthenticateRequest,
485 ) -> Result<Response<AuthenticateResponse>, Status> {
486 self.principal_of(request_id, &payload)
487 .await
488 .map(Response::new)
489 .map_err(|error_value| error::status(&error_value, request_id))
490 }
491
492 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
493 async fn verify_credential_inner(
494 &self,
495 request_id: Option<&str>,
496 payload: VerifyCredentialRequest,
497 ) -> Result<Response<VerifyCredentialResponse>, Status> {
498 let auth_request = AuthenticateRequest {
499 credential: payload.credential,
500 required_scopes: payload.required_scopes,
501 min_security_version: payload.min_security_version,
502 require_mfa: payload.require_mfa,
503 expected_audience: payload.expected_audience,
504 };
505 match self.principal_of(request_id, &auth_request).await {
506 Ok(_) => Ok(Response::new(VerifyCredentialResponse {
507 valid: true,
508 reason: Code::Unspecified as i32,
509 current_security_version: 0,
510 retry_after_ms: 0,
511 })),
512 Err(reason) => {
513 // 数据库/缓存/邮件故障不是「凭据无效」:必须作为可重试错误上抛。
514 if error::is_infrastructure(&reason) {
515 return Err(error::status(&reason, request_id));
516 }
517 let code = error::code_of(&reason);
518 let credential_failure = matches!(
519 reason,
520 AuthError::MalformedRequest | AuthError::InvalidAccessToken
521 );
522 if error::tonic_code(code) == tonic::Code::InvalidArgument && !credential_failure {
523 return Err(error::status_of(
524 Code::InvalidArgument,
525 reason.message(),
526 request_id,
527 ));
528 }
529 let current_security_version = match &reason {
530 AuthError::SecurityVersionStale { current } => *current,
531 _ => 0,
532 };
533 Ok(Response::new(VerifyCredentialResponse {
534 valid: false,
535 reason: code as i32,
536 current_security_version,
537 retry_after_ms: 0,
538 }))
539 }
540 }
541 }
542
543 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
544244 async fn get_user_public_inner(
545245 &self,
546246 request_id: Option<&str>,
@@ -555,9 +255,8 @@
555255 .map_err(|error_value| error::status(&error_value, request_id))?
556256 .ok_or_else(|| error::status(&AuthError::UserNotFound, request_id))?;
557257 let email = user.email.clone();
558 let avatar = self.svc.avatar_url(user.id).await.unwrap_or(None);
559258 Ok(Response::new(GetUserPublicResponse {
560 user: Some(store::user_public(&user, email, avatar)),
259 user: Some(store::user_public(&user, email, None)),
561260 }))
562261 }
563262
@@ -593,19 +292,9 @@
593292 .all(self.svc.db().read())
594293 .await
595294 .map_err(|error_value| error::status(&AuthError::from(error_value), request_id))?;
596 // 头像并发拉取:批内串行等待会把尾延迟累加到整体响应时间。
597 let avatars = futures_util::future::join_all(
598 rows.iter()
599 .map(|user| async move { self.svc.avatar_url(user.id).await.unwrap_or(None) }),
600 )
601 .await;
602295 let mut users = Vec::with_capacity(unique.len());
603 for (index, user) in rows.iter().enumerate() {
604 users.push(store::user_public(
605 user,
606 user.email.clone(),
607 avatars[index].clone(),
608 ));
296 for user in &rows {
297 users.push(store::user_public(user, user.email.clone(), None));
609298 }
610299 Ok(Response::new(BatchGetUserPublicResponse { users }))
611300 }
Modified lib/auth/src/server/grpc/mod.rs lib/auth/src/server/grpc/mod.rs +3 −101 View lib/auth/src/server/grpc/mod.rs
@@ -1,4 +1,3 @@
1pub mod access_key;
21pub mod agreement;
32pub mod audit;
43pub mod authority;
@@ -6,115 +5,18 @@
65pub mod cache_maintenance;
76pub mod context;
87pub mod convert;
9pub mod email;
108pub mod error;
119pub mod identity;
12pub mod key_rotation;
1310pub mod mfa;
1411pub mod organization;
15pub mod service_token;
1612pub mod session;
1713pub mod ssh_key;
1814pub mod store;
19pub mod token;
20
21use std::net::SocketAddr;
2215
23use thiserror::Error;
24use tonic::transport::Server;
25use tonic::transport::server::Router;
26use tonic_health::{ServingStatus, server};
27use tonic_reflection::server::Builder as ReflectionBuilder;
2816use tower::layer::util::{Identity, Stack};
2917
30use crate::server::AuthSvc;
31use crate::server::grpc::access_key::AccessKeyApi;
32use crate::server::grpc::agreement::AgreementApi;
33use crate::server::grpc::audit::AuditApi;
34use crate::server::grpc::authority::AuthorityApi;
35use crate::server::grpc::authorization::AuthorizationApi;
36use crate::server::grpc::cache_maintenance::CacheMaintenanceApi;
37use crate::server::grpc::email::EmailApi;
38use crate::server::grpc::identity::IdentityApi;
39use crate::server::grpc::key_rotation::KeyRotationApi;
40use crate::server::grpc::mfa::MfaApi;
41use crate::server::grpc::organization::{OrganizationAdminApi, OrganizationApi};
42use crate::server::grpc::session::SessionApi;
43use crate::server::grpc::ssh_key::SshKeyApi;
44use crate::server::grpc::token::TokenApi;
18pub type GrpcRouter = tonic::transport::Server<Stack<crate::oltp::GrpcRequestLog, Identity>>;
4519
46pub const DEFAULT_MAX_MESSAGE_SIZE: usize = 4 * 1024 * 1024;
47pub const HEALTH_SERVICE: &str = "";
48
49pub const IMPLEMENTED_SERVICES: &[&str] = &[
50 "auth.v1.AccessKeyService",
51 "auth.v1.AgreementService",
52 "auth.v1.AuthorizationService",
53 "auth.v1.IdentityService",
54 "auth.v1.MfaService",
55 "auth.v1.OrganizationService",
56 "auth.v1.SessionService",
57 "auth.v1.SshKeyService",
58 "auth.v1.TokenService",
59 "auth.internal.v1.AuditService",
60 "auth.internal.v1.AuthorityService",
61 "auth.internal.v1.CacheMaintenanceService",
62 "auth.internal.v1.EmailService",
63 "auth.internal.v1.KeyRotationService",
64 "auth.internal.v1.OrganizationAdminService",
65];
66
67#[derive(Debug, Error)]
68pub enum GrpcError {
69 #[error("grpc transport error: {0}")]
70 Transport(#[from] tonic::transport::Error),
71 #[error("grpc reflection error: {0}")]
72 Reflection(String),
73}
74
75pub type GrpcResult<T> = Result<T, GrpcError>;
76
77pub type GrpcRouter = Router<Stack<crate::oltp::GrpcRequestLog, Identity>>;
78
79pub async fn router(svc: AuthSvc) -> GrpcResult<GrpcRouter> {
80 let (reporter, health) = server::health_reporter();
81 reporter
82 .set_service_status(HEALTH_SERVICE, ServingStatus::Serving)
83 .await;
84 for service in IMPLEMENTED_SERVICES {
85 reporter
86 .set_service_status(*service, ServingStatus::Serving)
87 .await;
88 }
89
90 let reflection = ReflectionBuilder::configure()
91 .register_encoded_file_descriptor_set(crate::protos::FILE_DESCRIPTOR_SET)
92 .build_v1()
93 .map_err(|error| GrpcError::Reflection(error.to_string()))?;
94
95 Ok(Server::builder()
96 .layer(crate::oltp::GrpcRequestLog)
97 .add_service(health)
98 .add_service(reflection)
99 .add_service(AgreementApi::new(svc.clone()).server())
100 .add_service(IdentityApi::new(svc.clone()).server())
101 .add_service(SessionApi::new(svc.clone()).server())
102 .add_service(TokenApi::new(svc.clone()).server())
103 .add_service(AccessKeyApi::new(svc.clone()).server())
104 .add_service(SshKeyApi::new(svc.clone()).server())
105 .add_service(MfaApi::new(svc.clone()).server())
106 .add_service(OrganizationApi::new(svc.clone()).server())
107 .add_service(OrganizationAdminApi::new(svc.clone()).server())
108 .add_service(AuthorizationApi::new(svc.clone()).server())
109 .add_service(KeyRotationApi::new(svc.clone()).server())
110 .add_service(AuthorityApi::new(svc.clone()).server())
111 .add_service(CacheMaintenanceApi::new(svc.clone()).server())
112 .add_service(EmailApi::new(svc.clone()).server())
113 .add_service(AuditApi::new(svc).server()))
114}
115
116pub async fn serve(addr: SocketAddr, svc: AuthSvc) -> GrpcResult<()> {
117 let router = router(svc).await?;
118 router.serve(addr).await?;
119 Ok(())
20pub fn router() -> GrpcRouter {
21 tonic::transport::Server::builder().layer(crate::oltp::GrpcRequestLog)
12022}
Modified lib/auth/src/server/grpc/session.rs lib/auth/src/server/grpc/session.rs +6 −0 View lib/auth/src/server/grpc/session.rs
@@ -195,6 +195,12 @@
195195 }));
196196 }
197197
198 if let Err(err) =
199 store::drop_session_by_id(self.svc.cache(), request.user_id, session_id).await
200 {
201 tracing::warn!(%err, %session_id, "failed to drop the revoked session state");
202 }
203
198204 if let Err(err) = store::audit(
199205 self.svc.db(),
200206 request.user_id,
Modified lib/auth/src/server/grpc/store.rs lib/auth/src/server/grpc/store.rs +92 −14 View lib/auth/src/server/grpc/store.rs
@@ -10,9 +10,23 @@
1010use crate::server::errors::{AuthError, AuthResult};
1111use crate::server::grpc::context::RequestMeta;
1212use crate::server::grpc::convert;
13use crate::server::http::access_token::types::ALLOWED_APP_SCOPES;
1413use crate::server::share::user as user_store;
1514
15pub const ALLOWED_APP_SCOPES: [&str; 12] = [
16 "user_name",
17 "ssh_key",
18 "access_key",
19 "assets",
20 "email",
21 "profile",
22 "theme",
23 "guild",
24 "event",
25 "avatar",
26 "repo_read",
27 "repo_write",
28];
29
1630pub const MAX_BATCH_USER_IDS: usize = 500;
1731
1832pub async fn find_user(
@@ -139,12 +153,16 @@
139153
140154/// 每个要求项都必须被授予,且任何一项为零值(未指定/未知)都视为不满足。
141155pub fn scopes_cover(granted: &[i32], required: &[i32]) -> bool {
142 crate::jwt::scope::valid(granted)
156 scope_valid(granted)
143157 && required.iter().all(|required| {
144 *required > 0 && crate::jwt::scope::valid(&[*required]) && granted.contains(required)
158 *required > 0 && scope_valid(&[*required]) && granted.contains(required)
145159 })
146160}
147161
162fn scope_valid(scopes: &[i32]) -> bool {
163 scopes.iter().all(|scope| *scope > 0)
164}
165
148166pub fn user_public(user: &users::Model, email: String, avatar_url: Option<String>) -> UserPublic {
149167 UserPublic {
150168 user_id: user.id,
@@ -256,17 +274,15 @@
256274 let key = crate::session::SessionKey::try_from(session_key.trim())
257275 .map_err(|_| AuthError::Unauthenticated)?;
258276 let store = crate::session::RedisStore::new(cache.clone());
259 Ok(store.load(&key).await?)
277 Ok(store.load(&key).await?.map(|(state, _)| state))
260278}
261279
262280pub fn now() -> DateTime<Utc> {
263281 Utc::now()
264282}
265283
266pub const SESSION_INDEX_PREFIX: &str = "auth:session:index:";
267
268pub fn session_index_key(user_id: i64) -> String {
269 format!("{SESSION_INDEX_PREFIX}{user_id}")
284pub fn session_index_key(cache: &crate::cache::Cache, user_id: i64) -> String {
285 cache.key(&["user:session", &user_id.to_string()])
270286}
271287
272288pub async fn index_session_key(
@@ -275,27 +291,89 @@
275291 session_key: &str,
276292 ttl: std::time::Duration,
277293) -> AuthResult<()> {
278 let index_key = session_index_key(user_id);
294 let index_key = session_index_key(cache, user_id);
279295 cache.sadd(&index_key, session_key).await?;
280296 cache.expire(&index_key, ttl).await?;
281297 Ok(())
282298}
283299
284300pub async fn session_index(cache: &crate::cache::Cache, user_id: i64) -> AuthResult<Vec<String>> {
285 Ok(cache.smembers(&session_index_key(user_id)).await?)
301 Ok(cache.smembers(&session_index_key(cache, user_id)).await?)
286302}
287303
288pub async fn drop_session_state(cache: &crate::cache::Cache, session_key: &str) -> AuthResult<()> {
304pub async fn drop_session_state(
305 cache: &crate::cache::Cache,
306 user_id: i64,
307 session_key: &str,
308) -> AuthResult<()> {
289309 use crate::session::{SessionKey, SessionStore};
290310
291311 let key =
292312 SessionKey::try_from(session_key.to_owned()).map_err(|_| AuthError::SessionNotFound)?;
293313 crate::session::RedisStore::new(cache.clone())
294 .delete(&key)
314 .delete(&key, Some(user_id))
295315 .await?;
296316 Ok(())
297317}
298318
319pub async fn refresh_session_version(
320 cache: &crate::cache::Cache,
321 user_id: i64,
322 session_id: Uuid,
323 version: i32,
324 ttl_secs: u64,
325) -> AuthResult<()> {
326 use crate::session::{RedisStore, Session, SessionKey, SessionStore};
327
328 let ttl = actix_web::cookie::time::Duration::seconds(ttl_secs.max(1) as i64);
329 let expected = session_id.to_string();
330 for key in session_index(cache, user_id).await? {
331 let Some(state) = load_session(cache, &key).await? else {
332 continue;
333 };
334 let diff = {
335 let session = Session::from_state(state);
336 if session.session_id().as_deref() != Some(expected.as_str()) {
337 continue;
338 }
339 session.set_security_version(version)?;
340 session.diff()
341 };
342 let key = SessionKey::try_from(key).map_err(|_| AuthError::SessionNotFound)?;
343 RedisStore::new(cache.clone())
344 .update(key, diff, &ttl, Some(user_id), Some(user_id))
345 .await?;
346 }
347 Ok(())
348}
349
350pub async fn drop_session_by_id(
351 cache: &crate::cache::Cache,
352 user_id: i64,
353 session_id: Uuid,
354) -> AuthResult<()> {
355 use crate::session::Session;
356
357 let expected = session_id.to_string();
358 for key in session_index(cache, user_id).await? {
359 let Some(state) = load_session(cache, &key).await? else {
360 continue;
361 };
362 let matches = Session::from_state(state).session_id().as_deref() == Some(expected.as_str());
363 if !matches {
364 continue;
365 }
366 if let Err(error) = drop_session_state(cache, user_id, &key).await {
367 tracing::warn!(user_id, %error, "session state drop failed");
368 continue;
369 }
370 if let Err(error) = cache.srem(&session_index_key(cache, user_id), &key).await {
371 tracing::warn!(user_id, %error, "session index cleanup failed");
372 }
373 }
374 Ok(())
375}
376
299377pub async fn drop_user_session_states(
300378 cache: &crate::cache::Cache,
301379 user_id: i64,
@@ -304,7 +382,7 @@
304382 use crate::session::Session;
305383 use futures_util::StreamExt;
306384
307 let index_key = session_index_key(user_id);
385 let index_key = session_index_key(cache, user_id);
308386 let dropped = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
309387 futures_util::stream::iter(session_index(cache, user_id).await?)
310388 .map(|key| {
@@ -328,7 +406,7 @@
328406 if !bound {
329407 return;
330408 }
331 if let Err(error) = drop_session_state(&cache, &key).await {
409 if let Err(error) = drop_session_state(&cache, user_id, &key).await {
332410 tracing::warn!(user_id, %error, "session state drop failed");
333411 return;
334412 }
Modified lib/auth/src/server/http/mod.rs lib/auth/src/server/http/mod.rs +0 −6 View lib/auth/src/server/http/mod.rs
@@ -1,8 +1,4 @@
1pub mod access_token;
2pub mod app_token;
31pub mod challenge;
4pub mod cors;
5pub mod health;
62pub mod login;
73pub mod logout;
84pub mod me;
@@ -11,6 +7,4 @@
117pub mod password_reset;
128pub mod register;
139pub mod router;
14pub mod socket_ticket;
1510pub mod ssh_key;
16pub mod token;
Modified lib/auth/src/server/http/openapi.rs lib/auth/src/server/http/openapi.rs +1 −11 View lib/auth/src/server/http/openapi.rs
@@ -4,7 +4,7 @@
44#[openapi(
55 info(
66 title = "auth",
7 description = "认证与账号服务:工作量证明、口令与验证码登录、二次验证、注册、口令重置、访问令牌与 SSH 公钥。",
7 description = "认证与账号服务:工作量证明、口令与验证码登录、二次验证、注册、口令重置与 SSH 公钥。",
88 version = env!("CARGO_PKG_VERSION")
99 ),
1010 paths(
@@ -19,16 +19,9 @@
1919 crate::server::http::register::handler::register,
2020 crate::server::http::password_reset::handler::password_reset_request,
2121 crate::server::http::password_reset::handler::password_reset,
22 crate::server::http::access_token::handler::access_token_list,
23 crate::server::http::access_token::handler::access_token_create,
24 crate::server::http::access_token::handler::access_token_revoke,
25 crate::server::http::app_token::handler::app_token_issue,
26 crate::server::http::token::handler::token_issue,
2722 crate::server::http::ssh_key::handler::ssh_key_list,
2823 crate::server::http::ssh_key::handler::ssh_key_add,
2924 crate::server::http::ssh_key::handler::ssh_key_delete,
30 crate::server::http::health::health,
31 crate::server::http::health::ready,
3225 crate::server::http::organization::handler::create_organization,
3326 crate::server::http::organization::handler::list_organizations,
3427 crate::server::http::organization::handler::get_organization,
@@ -69,9 +62,6 @@
6962 crate::server::http::organization::handler::redeem_invite,
7063 ),
7164 components(schemas(
72 crate::server::http::health::HealthResponse,
73 crate::server::http::health::ReadinessResponse,
74 crate::server::http::health::ComponentCheck,
7565 crate::server::http::organization::types::OrganizationSummary,
7666 crate::server::http::organization::types::MemberSummary,
7767 crate::server::http::organization::types::RoleSummary,
Modified lib/auth/src/server/http/router.rs lib/auth/src/server/http/router.rs +2 −39 View lib/auth/src/server/http/router.rs
@@ -1,23 +1,10 @@
11use actix_web::web;
22
33pub fn configure(cfg: &mut web::ServiceConfig) {
4 cfg.route(
5 "/health",
6 web::get().to(crate::server::http::health::health),
7 );
8 cfg.route("/ready", web::get().to(crate::server::http::health::ready));
9 cfg.service(web::scope("/api/v1").configure(api));
4 cfg.service(web::scope("/api/v1").configure(configure_api));
105}
116
12fn api(cfg: &mut web::ServiceConfig) {
13 cfg.route(
14 "/oauth/socket-tickets",
15 web::post().to(crate::server::http::socket_ticket::issue),
16 );
17 cfg.route(
18 "/oauth/socket-tickets",
19 web::method(actix_web::http::Method::OPTIONS).to(crate::server::http::cors::preflight),
20 );
7pub fn configure_api(cfg: &mut web::ServiceConfig) {
218 cfg.route(
229 "/oauth/challenge",
2310 web::post().to(crate::server::http::challenge::handler::challenge),
@@ -61,30 +48,6 @@
6148 cfg.route(
6249 "/oauth/password/reset/confirm",
6350 web::post().to(crate::server::http::password_reset::handler::password_reset),
64 );
65 cfg.route(
66 "/oauth/access-tokens",
67 web::get().to(crate::server::http::access_token::handler::access_token_list),
68 );
69 cfg.route(
70 "/oauth/access-tokens",
71 web::post().to(crate::server::http::access_token::handler::access_token_create),
72 );
73 cfg.route(
74 "/oauth/access-tokens/{token_id}",
75 web::delete().to(crate::server::http::access_token::handler::access_token_revoke),
76 );
77 cfg.route(
78 "/oauth/access-tokens/{token_id}/rotate",
79 web::post().to(crate::server::http::access_token::handler::access_token_rotate),
80 );
81 cfg.route(
82 "/oauth/app-tokens",
83 web::post().to(crate::server::http::app_token::handler::app_token_issue),
84 );
85 cfg.route(
86 "/oauth/session/token",
87 web::post().to(crate::server::http::token::handler::token_issue),
8851 );
8952 cfg.route(
9053 "/oauth/ssh-keys",
Modified lib/auth/src/server/share/mod.rs lib/auth/src/server/share/mod.rs +0 −1 View lib/auth/src/server/share/mod.rs
@@ -1,7 +1,6 @@
11pub mod audit;
22pub mod codes;
33pub mod crypto;
4pub mod issue;
54pub mod mfa;
65pub mod net;
76pub mod password;
Modified lib/auth/src/server/account_lifecycle.rs lib/auth/src/server/account_lifecycle.rs +6 −9 View lib/auth/src/server/account_lifecycle.rs
@@ -5,9 +5,7 @@
55};
66
77use crate::models::space::{OrganizationStatus, organization_members, organizations};
8use crate::models::users::{
9 user_access_tokens, user_mfa, user_mfa_backup_codes, user_sessions, user_ssh_keys, users,
10};
8use crate::models::users::{user_mfa, user_mfa_backup_codes, user_sessions, user_ssh_keys, users};
119use crate::server::AuthSvc;
1210use crate::server::errors::{AuthError, AuthResult};
1311
@@ -119,6 +117,11 @@
119117 active.version = Set(version.saturating_add(1));
120118 active.update(&txn).await?;
121119 txn.commit().await?;
120 if let Err(error) =
121 crate::server::grpc::store::drop_user_session_states(self.cache(), user_id, None).await
122 {
123 tracing::warn!(%error, %user_id, "failed to drop purged account sessions");
124 }
122125 tracing::info!(%user_id, %request_id, "account purged");
123126 Ok(())
124127 }
@@ -133,12 +136,6 @@
133136 .col_expr(user_sessions::Column::RevokedAt, Expr::value(now))
134137 .filter(user_sessions::Column::UserId.eq(user_id))
135138 .filter(user_sessions::Column::RevokedAt.is_null())
136 .exec(txn)
137 .await?;
138 user_access_tokens::Entity::update_many()
139 .col_expr(user_access_tokens::Column::RevokedAt, Expr::value(now))
140 .filter(user_access_tokens::Column::UserId.eq(user_id))
141 .filter(user_access_tokens::Column::RevokedAt.is_null())
142139 .exec(txn)
143140 .await?;
144141 user_ssh_keys::Entity::update_many()
Modified lib/auth/src/server/auth_svc.rs lib/auth/src/server/auth_svc.rs +16 −60 View lib/auth/src/server/auth_svc.rs
@@ -1,12 +1,10 @@
11use std::sync::Arc;
22
33use crate::cache::Cache;
4use crate::config::app::AppRegistry;
54use crate::config::auth::AuthConfig;
6use crate::config::jwt::JwtConfig;
75use crate::config::pow::PowConfig;
86use crate::db::DbConn;
9use crate::email::EmailService;
7use crate::email::MailPublisher;
108use crate::events::{EventHandler, Labels, label};
119use serde::Serialize;
1210
@@ -39,13 +37,10 @@
3937pub struct AuthSvc {
4038 db: DbConn,
4139 cache: Cache,
42 email: Option<EmailService>,
40 mail: Option<MailPublisher>,
4341 events: Option<EventHandler>,
4442 auth: Arc<AuthConfig>,
4543 pow: Arc<PowConfig>,
46 apps: Arc<AppRegistry>,
47 signing: Arc<crate::server::keys::SigningState>,
48 jwt: crate::jwt::JwtState,
4944 session_max_age_secs: u64,
5045}
5146
@@ -54,44 +49,21 @@
5449 pub async fn new(
5550 db: DbConn,
5651 cache: Cache,
57 email: Option<EmailService>,
52 mail: Option<MailPublisher>,
5853 events: Option<EventHandler>,
5954 auth: AuthConfig,
6055 pow: PowConfig,
61 apps: AppRegistry,
62 jwt_config: JwtConfig,
6356 session_max_age_secs: u64,
6457 ) -> AuthResult<Self> {
65 let rpc_key = auth.rpc_key.trim();
66 if !rpc_key.is_empty() && rpc_key.len() < 32 {
67 return Err(AuthError::Unavailable(
68 "auth.rpc_key must be at least 32 characters".to_owned(),
69 ));
70 }
71 if rpc_key.starts_with("REPLACE_WITH_") {
72 return Err(AuthError::Unavailable(
73 "auth.rpc_key is still set to the placeholder value".to_owned(),
74 ));
75 }
76 let signing = crate::server::keys::SigningState::from_config(&jwt_config)?;
77 let jwt_state = crate::jwt::JwtState::load(&jwt_config)
78 .await
79 .map_err(|error| AuthError::Unavailable(error.to_string()))?;
80 let svc = Self {
58 Ok(Self {
8159 db,
8260 cache,
83 email,
61 mail,
8462 events,
8563 auth: Arc::new(auth),
8664 pow: Arc::new(pow),
87 apps: Arc::new(apps),
88 signing: Arc::new(signing),
89 jwt: jwt_state,
9065 session_max_age_secs: session_max_age_secs.max(1),
91 };
92 crate::jwt::authority::install(Arc::new(svc.clone()))
93 .map_err(|error| AuthError::Unavailable(error.to_string()))?;
94 Ok(svc)
66 })
9567 }
9668
9769 pub fn db(&self) -> &DbConn {
@@ -102,8 +74,8 @@
10274 &self.cache
10375 }
10476
105 pub fn email(&self) -> Option<&EmailService> {
106 self.email.as_ref()
77 pub fn mail(&self) -> Option<&MailPublisher> {
78 self.mail.as_ref()
10779 }
10880
10981 pub fn auth(&self) -> &AuthConfig {
@@ -114,18 +86,6 @@
11486 &self.pow
11587 }
11688
117 pub fn apps(&self) -> &AppRegistry {
118 &self.apps
119 }
120
121 pub fn signing(&self) -> &crate::server::keys::SigningState {
122 &self.signing
123 }
124
125 pub fn jwt(&self) -> &crate::jwt::JwtState {
126 &self.jwt
127 }
128
12989 pub fn events(&self) -> Option<&EventHandler> {
13090 self.events.as_ref()
13191 }
@@ -259,17 +219,13 @@
259219 html: &str,
260220 request_id: Option<&str>,
261221 ) -> AuthResult<()> {
262 match self.email.as_ref() {
263 Some(service) => {
264 service
265 .enqueue_mail(to, subject, text, html, request_id)
266 .await?;
267 Ok(())
268 }
269 None => {
270 tracing::warn!(to, subject, "auth email service is not configured");
271 Ok(())
272 }
273 }
222 let Some(mail) = self.mail.as_ref() else {
223 return Err(AuthError::Unavailable(
224 "mail publisher is not configured".to_owned(),
225 ));
226 };
227 mail.send_mail(to, subject, text, html, request_id)
228 .await
229 .map_err(|error| AuthError::Internal(error.to_string()))
274230 }
275231}
Modified lib/auth/src/server/authority.rs lib/auth/src/server/authority.rs +55 −111 View lib/auth/src/server/authority.rs
@@ -1,8 +1,5 @@
1use crate::jwt::authority::{AccessRecord, Authority, UserRecord};
2use crate::jwt::{AppClaims, JwtError};
31use crate::models::users::{user_sessions, users};
42use crate::session::Session;
5use async_trait::async_trait;
63use chrono::{DateTime, Duration, Utc};
74use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter, Set};
85use uuid::Uuid;
@@ -10,8 +7,6 @@
107use crate::server::share::{crypto, user as store};
118use crate::server::{AuthError, AuthResult, AuthSvc};
129
13const MAX_BATCH_PROFILES: usize = store::MAX_BATCH_USER_IDS;
14
1510/// 会话凭据摘要的算法标识,落在 `user_sessions.hash_key_id`。
1611pub const SESSION_HASH_KEY_ID: &str = "logical-session-v1";
1712
@@ -20,34 +15,14 @@
2015 crypto::sha256_hex(id.to_string().as_bytes())
2116}
2217
23pub(crate) fn record(user: users::Model) -> UserRecord {
24 UserRecord {
25 id: user.id,
26 username: user.username,
27 lowername: user.lowername,
28 displayname: user.displayname,
29 birth_date: user.birth_date,
30 email: user.email,
31 public_show_email: user.public_show_email,
32 email_verified_at: user.email_verified_at,
33 allow_use: user.allow_use,
34 forbid_login: user.forbid_login,
35 forbid_login_reason: user.forbid_login_reason,
36 endtime_forbid_login_at: user.endtime_forbid_login_at,
37 is_admin: user.is_admin,
38 bot: user.bot,
39 system: user.system,
40 created_at: user.created_at,
41 updated_at: user.updated_at,
42 security_version: user.security_version,
43 version: user.version,
44 deleted_at: user.deleted_at,
45 }
46}
47
48fn invalid(error: impl std::fmt::Display) -> JwtError {
49 tracing::debug!(%error, "authority check failed");
50 JwtError::Revoked
18fn account_active(user: &users::Model) -> bool {
19 user.id > 0
20 && user.deleted_at.is_none()
21 && user.allow_use
22 && (!user.forbid_login
23 || user
24 .endtime_forbid_login_at
25 .is_none_or(|until| until > Utc::now()))
5126}
5227
5328impl AuthSvc {
@@ -93,42 +68,39 @@
9368 version: i32,
9469 session_id: &str,
9570 request_id: Option<&str>,
96 ) -> Result<AccessRecord, JwtError> {
71 ) -> AuthResult<(users::Model, bool)> {
9772 // security_version 判定一律读主库:副本延迟会让刚吊销的旧版本短暂放行。
9873 let user = users::Entity::find_by_id(user_id)
9974 .one(self.db().write())
100 .await
101 .map_err(invalid)?
102 .ok_or(JwtError::Revoked)?;
103 let user = record(user);
104 user.require_active()?;
75 .await?
76 .ok_or(AuthError::Unauthenticated)?;
77 if !account_active(&user) {
78 return Err(AuthError::Unauthenticated);
79 }
10580 if version <= 0 || version != user.security_version {
106 return Err(JwtError::Revoked);
81 return Err(AuthError::Unauthenticated);
10782 }
108 let id = Uuid::parse_str(session_id).map_err(invalid)?;
83 let id = Uuid::parse_str(session_id).map_err(|_| AuthError::Unauthenticated)?;
10984 let row = user_sessions::Entity::find_by_id(id)
11085 .one(self.db().write())
111 .await
112 .map_err(invalid)?
113 .ok_or(JwtError::Revoked)?;
86 .await?
87 .ok_or(AuthError::Unauthenticated)?;
11488 // `token_hash` 是会话凭据的摘要:只有拿着明文会话 ID 的一方能算出来。
11589 // 不校验它,单有数据库读权限的人就能直接拿行里的 ID 复会话。
11690 if !crate::server::share::crypto::constant_time_eq(
11791 row.token_hash.as_bytes(),
11892 session_token_hash(id).as_bytes(),
11993 ) {
120 return Err(JwtError::Revoked);
94 return Err(AuthError::Unauthenticated);
12195 }
12296 if row.user_id != user_id
12397 || row.security_version != version
12498 || row.revoked_at.is_some()
12599 || row.expires_at <= Utc::now()
126100 {
127 return Err(JwtError::Revoked);
101 return Err(AuthError::Unauthenticated);
128102 }
129 let mut record = AccessRecord::from(&user);
130 record.mfa_verified = row.mfa_verified_at.is_some();
131 Ok(record)
103 Ok((user, row.mfa_verified_at.is_some()))
132104 }
133105
134106 #[tracing::instrument(skip_all, fields(request_id = %request_id.unwrap_or_default()))]
@@ -144,9 +116,9 @@
144116 let id = session
145117 .get::<String>("auth_session_id")?
146118 .ok_or(AuthError::Unauthenticated)?;
147 self.check_session(user_id, version, &id, request_id)
148 .await
149 .map_err(|_| AuthError::Unauthenticated)?;
119 let _ = self
120 .check_session(user_id, version, &id, request_id)
121 .await?;
150122 Ok(user_id)
151123 }
152124
@@ -168,33 +140,15 @@
168140 .await?;
169141 Ok(row.map(|row| row.created_at))
170142 }
171}
172143
173#[async_trait]
174impl Authority for AuthSvc {
175 async fn validate(&self, _: &str, claims: &AppClaims) -> Result<AccessRecord, JwtError> {
176 self.check_session(
177 claims.user_id,
178 claims.security_version,
179 claims.session_id.as_deref().ok_or(JwtError::Revoked)?,
180 crate::envelope::context::request_id().as_deref(),
181 )
182 .await
183 }
184
185 async fn user(&self, user_id: i64) -> Result<UserRecord, JwtError> {
186 let user = users::Entity::find_by_id(user_id)
144 pub async fn user(&self, user_id: i64) -> AuthResult<users::Model> {
145 users::Entity::find_by_id(user_id)
187146 .one(self.db().read())
188 .await
189 .map_err(invalid)?
190 .ok_or(JwtError::Revoked)?;
191 Ok(record(user))
147 .await?
148 .ok_or(AuthError::UserNotFound)
192149 }
193150
194 async fn users(&self, user_ids: &[i64]) -> Result<Vec<UserRecord>, JwtError> {
195 if user_ids.len() > MAX_BATCH_PROFILES {
196 return Err(JwtError::Malformed);
197 }
151 pub async fn users(&self, user_ids: &[i64]) -> AuthResult<Vec<users::Model>> {
198152 let mut unique: Vec<i64> = Vec::with_capacity(user_ids.len());
199153 for user_id in user_ids.iter().copied().filter(|user_id| *user_id > 0) {
200154 if !unique.contains(&user_id) {
@@ -204,43 +158,27 @@
204158 if unique.is_empty() {
205159 return Ok(Vec::new());
206160 }
207 let rows = users::Entity::find()
161 Ok(users::Entity::find()
208162 .filter(users::Column::Id.is_in(unique))
209163 .all(self.db().read())
210 .await
211 .map_err(invalid)?;
212 Ok(rows.into_iter().map(record).collect())
213 }
214
215 async fn session(
216 &self,
217 user_id: i64,
218 version: i32,
219 session_id: &str,
220 ) -> Result<AccessRecord, JwtError> {
221 self.check_session(
222 user_id,
223 version,
224 session_id,
225 crate::envelope::context::request_id().as_deref(),
226 )
227 .await
164 .await?)
228165 }
229166
230 async fn update(&self, user_id: i64, patch: serde_json::Value) -> Result<UserRecord, JwtError> {
231 let user = store::load_active_user(self.db(), user_id)
232 .await
233 .map_err(invalid)?;
167 pub async fn update(&self, user_id: i64, patch: serde_json::Value) -> AuthResult<users::Model> {
168 let user = store::load_active_user(self.db(), user_id).await?;
234169 let version = patch
235170 .get("version")
236 .and_then(|v| v.as_i64())
237 .ok_or(JwtError::Malformed)?;
171 .and_then(|value| value.as_i64())
172 .ok_or(AuthError::MalformedRequest)?;
238173 if i64::from(user.version) != version {
239 return Err(JwtError::Malformed);
174 return Err(AuthError::VersionMismatch {
175 current: user.version,
176 });
240177 }
241178 let mut active = user.clone().into_active_model();
242 if let Some(name) = patch.get("username").and_then(|v| v.as_str()) {
243 let name = crate::server::share::validate::validate_username(name).map_err(invalid)?;
179 if let Some(name) = patch.get("username").and_then(|value| value.as_str()) {
180 let name = crate::server::share::validate::validate_username(name)
181 .map_err(|_| AuthError::InvalidUsername)?;
244182 active.lowername = Set(name.to_lowercase());
245183 active.username = Set(name);
246184 }
@@ -248,27 +186,33 @@
248186 active.displayname = Set(match value.as_str() {
249187 Some(value) => Some(
250188 crate::server::share::validate::validate_display_name(value)
251 .map_err(invalid)?,
189 .map_err(|_| AuthError::InvalidDisplayname)?,
252190 ),
253191 None if value.is_null() => None,
254 _ => return Err(JwtError::Malformed),
192 _ => return Err(AuthError::MalformedRequest),
255193 });
256194 }
257195 if let Some(value) = patch.get("public_show_email") {
258 active.public_show_email = Set(value.as_bool().ok_or(JwtError::Malformed)?);
196 active.public_show_email = Set(value.as_bool().ok_or(AuthError::MalformedRequest)?);
259197 }
260 active.version = Set(user.version.checked_add(1).ok_or(JwtError::Malformed)?);
198 active.version = Set(user
199 .version
200 .checked_add(1)
201 .ok_or(AuthError::VersionMismatch {
202 current: user.version,
203 })?);
261204 active.updated_at = Set(Utc::now());
262205 let updated = users::Entity::update_many()
263206 .set(active)
264207 .filter(users::Column::Id.eq(user_id))
265208 .filter(users::Column::Version.eq(user.version))
266209 .exec_with_returning(self.db().write())
267 .await
268 .map_err(invalid)?
210 .await?
269211 .pop()
270 .ok_or(JwtError::Malformed)?;
212 .ok_or(AuthError::VersionMismatch {
213 current: user.version,
214 })?;
271215 crate::server::http::me::service::invalidate_me_cache(self.cache(), user_id).await;
272 Ok(record(updated))
216 Ok(updated)
273217 }
274218}
Modified lib/auth/src/server/migrate.rs lib/auth/src/server/migrate.rs +2 −0 View lib/auth/src/server/migrate.rs
@@ -9,6 +9,8 @@
99 "DROP TABLE IF EXISTS oauth_refresh_tokens",
1010 "DROP TABLE IF EXISTS oauth_consents",
1111 "DROP TABLE IF EXISTS oauth_clients",
12 "DROP TABLE IF EXISTS user_access_tokens",
13 "DROP TABLE IF EXISTS service_token_revocations",
1214 ])
1315 .after([
1416 // 邮箱查询一律走 lower(email),表达式唯一索引把大小写变体挡在数据库层。
Modified lib/auth/src/server/mod.rs lib/auth/src/server/mod.rs +1 −3 View lib/auth/src/server/mod.rs
@@ -3,7 +3,6 @@
33pub mod errors;
44pub mod grpc;
55pub mod http;
6pub mod keys;
76pub mod migrate;
87pub mod pow;
98pub mod share;
@@ -15,6 +14,5 @@
1514pub use auth_svc::AuthSvc;
1615
1716pub use http::{
18 access_token, app_token, challenge, health, login, logout, me, openapi, organization,
19 password_reset, register, router, socket_ticket, ssh_key, token,
17 challenge, login, logout, me, openapi, organization, password_reset, register, router, ssh_key,
2018};
Modified lib/auth/src/lib.rs lib/auth/src/lib.rs +1 −2 View lib/auth/src/lib.rs
@@ -6,8 +6,8 @@
66
77#![recursion_limit = "512"]
88
9pub mod assets;
910pub mod client;
10pub mod runtime;
1111pub mod server;
1212
1313pub use cache;
@@ -22,4 +22,3 @@
2222pub use proto as protos;
2323pub use queue;
2424pub use session;
25pub use token as jwt;
Modified lib/auth/Cargo.toml lib/auth/Cargo.toml +0 −4 View lib/auth/Cargo.toml
@@ -19,7 +19,6 @@
1919proto = { workspace = true }
2020queue = { workspace = true }
2121session = { workspace = true }
22token = { workspace = true }
2322tokio-stream = { version = "0.1", features = ["net"] }
2423actix-web = "4.16.0"
2524aes-gcm = "0.11.1"
@@ -29,7 +28,6 @@
2928base64 = "0.23.1"
3029bytes = "1.12.1"
3130chrono = { version = "0.4.45", features = ["serde"] }
32ed25519-dalek = "2.2.0"
3331figment = { version = "0.10", default-features = false, features = [
3432 "toml",
3533 "json",
@@ -90,9 +88,7 @@
9088tokio = { version = "1.53.3", features = ["full"] }
9189tokio-util = "0.7.20"
9290tonic = { version = "0.14.6", features = ["tls-ring"] }
93tonic-health = "0.14.6"
9491tonic-prost = "0.14.6"
95tonic-reflection = "0.14.6"
9692tower = "0.5.3"
9793tracing = "0.1.44"
9894tracing-opentelemetry = "0.33.0"
Modified lib/chat/src/handlers/attachments.rs lib/chat/src/handlers/attachments.rs +2 −2 View lib/chat/src/handlers/attachments.rs
@@ -1,9 +1,9 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, Response, State};
24use export::rest::{AppResponseData, NoData};
35use imaging::layout::ImageVariant;
46use serde::Deserialize;
5use token::Session;
6use token::share::session;
77use utoipa::{IntoParams, ToSchema};
88use uuid::Uuid;
99
Modified lib/chat/src/handlers/bookmarks.rs lib/chat/src/handlers/bookmarks.rs +2 −2 View lib/chat/src/handlers/bookmarks.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/dms.rs lib/chat/src/handlers/dms.rs +2 −2 View lib/chat/src/handlers/dms.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/drafts.rs lib/chat/src/handlers/drafts.rs +2 −2 View lib/chat/src/handlers/drafts.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/emojis.rs lib/chat/src/handlers/emojis.rs +2 −2 View lib/chat/src/handlers/emojis.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Response, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/messages.rs lib/chat/src/handlers/messages.rs +2 −2 View lib/chat/src/handlers/messages.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/presence.rs lib/chat/src/handlers/presence.rs +2 −2 View lib/chat/src/handlers/presence.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55
66use crate::errors::ApiError;
77use crate::services::presence::{PresenceDto, SetPresenceCmd};
Modified lib/chat/src/handlers/reactions.rs lib/chat/src/handlers/reactions.rs +2 −2 View lib/chat/src/handlers/reactions.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/read_state.rs lib/chat/src/handlers/read_state.rs +2 −2 View lib/chat/src/handlers/read_state.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/reminders.rs lib/chat/src/handlers/reminders.rs +2 −2 View lib/chat/src/handlers/reminders.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/room_admin.rs lib/chat/src/handlers/room_admin.rs +2 −2 View lib/chat/src/handlers/room_admin.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/rooms.rs lib/chat/src/handlers/rooms.rs +2 −2 View lib/chat/src/handlers/rooms.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/settings.rs lib/chat/src/handlers/settings.rs +2 −2 View lib/chat/src/handlers/settings.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/threads.rs lib/chat/src/handlers/threads.rs +2 −2 View lib/chat/src/handlers/threads.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/handlers/voice.rs lib/chat/src/handlers/voice.rs +2 −2 View lib/chat/src/handlers/voice.rs
@@ -1,10 +1,10 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{HeaderMap, Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
35use livekit_api::access_token::TokenVerifier;
46use livekit_api::webhooks::WebhookReceiver;
57use serde::Deserialize;
6use token::Session;
7use token::share::session;
88use uuid::Uuid;
99
1010use crate::errors::ApiError;
Modified lib/chat/src/handlers/webhooks.rs lib/chat/src/handlers/webhooks.rs +2 −2 View lib/chat/src/handlers/webhooks.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, Path, Query, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/chat/src/services/service.rs lib/chat/src/services/service.rs +2 −2 View lib/chat/src/services/service.rs
@@ -80,12 +80,12 @@
8080 text: &str,
8181 html: &str,
8282 ) -> Result<(), ChatError> {
83 let Some(client) = self.state.email_rpc.as_ref() else {
83 let Some(client) = self.state.mail.as_ref() else {
8484 tracing::warn!(to, "email rpc disabled; skipping chat mail");
8585 return Ok(());
8686 };
8787 client
88 .send_mail(to, subject, text, html)
88 .send_mail(to, subject, text, html, None)
8989 .await
9090 .map_err(|error| ChatError::Internal(format!("email send failed: {error}")))
9191 }
Modified lib/chat/src/share/guard.rs lib/chat/src/share/guard.rs +1 −1 View lib/chat/src/share/guard.rs
@@ -1 +1 @@
1pub use token::share::guard::session_guard as chat_guard;
1pub use ::session::share::guard::session_guard as chat_guard;
Modified lib/chat/Cargo.toml lib/chat/Cargo.toml +1 −1 View lib/chat/Cargo.toml
@@ -12,7 +12,7 @@
1212models = { workspace = true }
1313queue = { workspace = true }
1414social = { workspace = true }
15token = { workspace = true }
15session = { workspace = true }
1616space = { workspace = true }
1717storage = { workspace = true }
1818actix-web = { workspace = true }
Modified lib/config/src/app/mod.rs lib/config/src/app/mod.rs +0 −2 View lib/config/src/app/mod.rs
@@ -1,7 +1,5 @@
11mod app_config;
2mod app_registry;
32mod key;
43
54pub use app_config::AppConfig;
6pub use app_registry::{AppRegistration, AppRegistry};
75pub use key::{AppKeyAlgorithm, AppKeyConfig, SecretMaterial};
Modified lib/config/src/auth.rs lib/config/src/auth.rs +0 −2 View lib/config/src/auth.rs
@@ -38,7 +38,6 @@
3838#[serde(default)]
3939pub struct AuthConfig {
4040 pub rpc_key: String,
41 pub socket_origins: Vec<String>,
4241 pub password_policy: PasswordPolicy,
4342 pub verify_code_ttl_secs: u64,
4443 pub verify_code_len: usize,
@@ -55,7 +54,6 @@
5554 fn default() -> Self {
5655 Self {
5756 rpc_key: String::new(),
58 socket_origins: Vec::new(),
5957 password_policy: PasswordPolicy::default(),
6058 verify_code_ttl_secs: 600,
6159 verify_code_len: 6,
Modified lib/config/src/email.rs lib/config/src/email.rs +30 −0 View lib/config/src/email.rs
@@ -22,6 +22,24 @@
2222 pub enqueue_timeout_ms: u64,
2323 pub retry_delay_ms: u64,
2424 pub max_attempts: u32,
25 #[serde(default = "default_mail_topic")]
26 pub mail_topic: String,
27 #[serde(default = "default_consumer_group")]
28 pub consumer_group: String,
29 #[serde(default = "default_max_reconsume")]
30 pub max_reconsume: u32,
31}
32
33fn default_mail_topic() -> String {
34 "gitdata-mail".to_owned()
35}
36
37fn default_consumer_group() -> String {
38 "gitdata-mail".to_owned()
39}
40
41fn default_max_reconsume() -> u32 {
42 5
2543}
2644
2745impl EmailPoolConfig {
@@ -38,6 +56,15 @@
3856 if !(1..=100).contains(&self.max_attempts) {
3957 return Err("email.max_attempts must be between 1 and 100".to_string());
4058 }
59 if self.mail_topic.trim().is_empty() {
60 return Err("email.mail_topic must not be blank".to_string());
61 }
62 if self.consumer_group.trim().is_empty() {
63 return Err("email.consumer_group must not be blank".to_string());
64 }
65 if !(1..=16).contains(&self.max_reconsume) {
66 return Err("email.max_reconsume must be between 1 and 16".to_string());
67 }
4168 Ok(())
4269 }
4370
@@ -58,6 +85,9 @@
5885 enqueue_timeout_ms: 5_000,
5986 retry_delay_ms: 2_000,
6087 max_attempts: 3,
88 mail_topic: default_mail_topic(),
89 consumer_group: default_consumer_group(),
90 max_reconsume: default_max_reconsume(),
6191 }
6292 }
6393}
Modified lib/config/src/lib.rs lib/config/src/lib.rs +0 −3 View lib/config/src/lib.rs
@@ -7,7 +7,6 @@
77pub mod git;
88pub mod internal;
99pub mod issues;
10pub mod jwt;
1110pub mod livekit;
1211pub mod pow;
1312pub mod push;
@@ -40,7 +39,6 @@
4039use crate::git::GitConfig;
4140use crate::internal::InternalConfig;
4241use crate::issues::IssueConfig;
43use crate::jwt::JwtConfig;
4442use crate::livekit::LiveKitConfig;
4543use crate::pow::PowConfig;
4644use crate::push::PushConfig;
@@ -69,7 +67,6 @@
6967 pub issues: IssueConfig,
7068 pub livekit: LiveKitConfig,
7169 pub git: GitConfig,
72 pub jwt: JwtConfig,
7370 pub session: SessionConfig,
7471 pub email: EmailConfig,
7572 pub apihost: ApihostConfig,
Modified lib/config/src/scoped.rs lib/config/src/scoped.rs +0 −3 View lib/config/src/scoped.rs
@@ -9,7 +9,6 @@
99use crate::error::ConfigError;
1010use crate::git::GitConfig;
1111use crate::issues::IssueConfig;
12use crate::jwt::JwtConfig;
1312use crate::livekit::LiveKitConfig;
1413use crate::pow::PowConfig;
1514use crate::push::PushConfig;
@@ -61,7 +60,6 @@
6160 pub issues: IssueConfig,
6261 pub git: GitConfig,
6362 pub email: EmailConfig,
64 pub jwt: JwtConfig,
6563 pub session: SessionConfig,
6664 pub apihost: ApihostSection,
6765 pub livekit: LiveKitConfig,
@@ -85,7 +83,6 @@
8583 issues: self.issues,
8684 git: self.git,
8785 email: self.email,
88 jwt: self.jwt,
8986 session: self.session,
9087 apihost: self.apihost,
9188 livekit: self.livekit,
Modified lib/config/src/server.rs lib/config/src/server.rs +0 −4 View lib/config/src/server.rs
@@ -5,17 +5,13 @@
55#[derive(Debug, Clone, Deserialize)]
66#[serde(default)]
77pub struct ServerConfig {
8 pub http_addr: SocketAddr,
98 pub grpc_addr: SocketAddr,
10 pub internal_grpc_addr: Option<SocketAddr>,
119}
1210
1311impl Default for ServerConfig {
1412 fn default() -> Self {
1513 Self {
16 http_addr: SocketAddr::from((Ipv4Addr::LOCALHOST, 8081)),
1714 grpc_addr: SocketAddr::from((Ipv4Addr::LOCALHOST, 8082)),
18 internal_grpc_addr: None,
1915 }
2016 }
2117}
Modified lib/config/src/session.rs lib/config/src/session.rs +7 −0 View lib/config/src/session.rs
@@ -12,12 +12,18 @@
1212 pub same_site: SameSite,
1313 #[serde(default)]
1414 pub trust_proxy: bool,
15 #[serde(default = "default_recheck_secs")]
16 pub recheck_secs: u64,
1517}
1618
1719fn default_anonymous_max_age() -> i64 {
1820 300
1921}
2022
23fn default_recheck_secs() -> u64 {
24 60
25}
26
2127impl Default for SessionConfig {
2228 fn default() -> Self {
2329 Self {
@@ -29,6 +35,7 @@
2935 secure: false,
3036 same_site: SameSite::default(),
3137 trust_proxy: false,
38 recheck_secs: default_recheck_secs(),
3239 }
3340 }
3441}
Modified lib/email/src/lib.rs lib/email/src/lib.rs +4 −10 View lib/email/src/lib.rs
@@ -1,20 +1,14 @@
1pub mod consumer;
12pub mod error;
23pub mod events;
3pub mod i18n;
4pub mod metrics;
5pub mod queue;
6pub mod service;
7pub mod template;
8pub mod templates;
4pub mod publisher;
95pub mod transport;
106
7pub use consumer::EmailConsumer;
118pub use error::EmailError;
129pub use events::{
1310 Attachment, BatchRecipient, EmailAddress, EmailFailed, EmailSent, RenderAndSendEmailRequest,
1411 SendBatchEmailRequest, SendEmailRequest,
1512};
16pub use i18n::UiLocale;
17pub use queue::{EmailQueue, Job, JobHandler, QueueSettings};
18pub use service::{EmailService, EmailServiceBuilder};
19pub use template::{TemplateFn, TemplateRegistry};
13pub use publisher::MailPublisher;
2014pub use transport::{EmailTransport, EmailTransportBuilder, build_message};
Modified lib/email/Cargo.toml lib/email/Cargo.toml +0 −7 View lib/email/Cargo.toml
@@ -5,18 +5,11 @@
55
66[dependencies]
77config = { workspace = true }
8db = { workspace = true }
9envelope = { workspace = true }
108events = { workspace = true }
119queue = { workspace = true }
12async-trait = { workspace = true }
1310base64 = { workspace = true }
1411bytes = { workspace = true }
15chrono = { version = "0.4.45", features = ["serde"] }
16futures-util = "0.3.34"
17http = "1.5.0"
1812lettre = { version = "0.11.23", default-features = false, features = ["smtp-transport", "tokio1-rustls", "rustls-tls", "builder", "pool"] }
19maud = { workspace = true }
2013serde = { workspace = true, features = ["derive"] }
2114serde_json = { workspace = true }
2215thiserror = { workspace = true }
Modified lib/envelope/src/middleware.rs lib/envelope/src/middleware.rs +1 −1 View lib/envelope/src/middleware.rs
@@ -6,7 +6,7 @@
66use actix_web::http::header::{HeaderMap, HeaderName, HeaderValue};
77use actix_web::{Error, HttpMessage};
88use futures_util::future::LocalBoxFuture;
9use session::{REQUEST_ID_HEADER, RequestId, validate_request_id};
9use ::session::{REQUEST_ID_HEADER, RequestId, validate_request_id};
1010use uuid::Uuid;
1111
1212use crate::context;
Modified lib/export/src/api_error.rs lib/export/src/api_error.rs +10 −8 View lib/export/src/api_error.rs
@@ -116,7 +116,7 @@
116116/// `IntoResponses` derive, envelope constructors, `IntoResponse`, and the
117117/// `From` impls shared by every crate (boxed self, `AppResponseData<()>`,
118118/// request rejections, `serde_json::Error`, `(StatusCode, &str)` and
119/// `token::SessionError`).
119/// `session::SessionError`).
120120///
121121/// The enum must contain an `Internal` variant; `log` labels server-side
122122/// warnings as "`<log> handler failed`".
@@ -295,16 +295,18 @@
295295 }
296296 }
297297
298 impl From<::token::SessionError> for $name {
299 fn from(error: ::token::SessionError) -> Self {
298 impl From<::session::SessionError> for $name {
299 fn from(error: ::session::SessionError) -> Self {
300300 match error {
301 ::token::SessionError::Unauthorized => {
301 ::session::SessionError::Unauthorized => {
302302 Self::build(401, Self::payload(401, "unauthenticated"))
303303 }
304 ::token::SessionError::Expired => Self::build(401, Self::payload(401, "token_expired")),
305 ::token::SessionError::Verifier(message) => {
306 ::tracing::debug!(error = %message, "bearer token rejected");
307 Self::build(401, Self::payload(401, "invalid_token"))
304 ::session::SessionError::Purged => {
305 Self::build(401, Self::payload(401, "session_revoked"))
306 }
307 other => {
308 ::tracing::error!(error = %other, "session backend error");
309 Self::build(500, Self::payload(500, "internal server error"))
308310 }
309311 }
310312 }
Modified lib/export/src/http.rs lib/export/src/http.rs +6 −1 View lib/export/src/http.rs
@@ -408,6 +408,11 @@
408408 self.erase()
409409 }
410410
411 pub fn setup(mut self, setup: impl FnOnce(Scope) -> Scope + 'static) -> Self {
412 self.setups.push(Box::new(setup));
413 self
414 }
415
411416 pub fn wrap(mut self, guard: Guard) -> Self {
412417 for route in &mut self.routes {
413418 route.guards.push(guard);
@@ -489,7 +494,7 @@
489494 move |request, next| {
490495 Box::pin(async move {
491496 match guard {
492 Guard::Session => token::share::guard::session_guard(request, next).await,
497 Guard::Session => session::share::guard::session_guard(request, next).await,
493498 Guard::ServiceKey => require_service_key(request, next).await,
494499 }
495500 })
Modified lib/export/src/lib.rs lib/export/src/lib.rs +4 −4 View lib/export/src/lib.rs
@@ -38,7 +38,7 @@
3838 pub storage: Arc<AppStorage>,
3939 pub config: AppConfig,
4040 pub kenauth: Option<Arc<auth::client::KenAuthClient>>,
41 pub email_rpc: Option<Arc<auth::client::KenAuthClient>>,
41 pub mail: Option<auth::email::MailPublisher>,
4242}
4343
4444impl AppState {
@@ -50,13 +50,14 @@
5050
5151 pub async fn with_config(config: AppConfig) -> Result<Self, ExportError> {
5252 let database = Arc::new(AppDatabase::connect(config.database.clone()).await?);
53 Self::with_identity(config, database, None).await
53 Self::with_identity(config, database, None, None).await
5454 }
5555
5656 pub async fn with_identity(
5757 config: AppConfig,
5858 database: Arc<AppDatabase>,
5959 identity: Option<Arc<auth::client::KenAuthClient>>,
60 mail: Option<auth::email::MailPublisher>,
6061 ) -> Result<Self, ExportError> {
6162 let mut redis = AppRedis::connect(config.redis.clone()).await?;
6263 // 入队点遍布各业务 crate,但只有这里有配置:把开关写进句柄,让
@@ -68,7 +69,6 @@
6869 if let Some(client) = &kenauth {
6970 identity_client::install(client.clone());
7071 }
71 let email_rpc = kenauth.clone();
7272
7373 Ok(Self {
7474 database,
@@ -76,7 +76,7 @@
7676 storage,
7777 config,
7878 kenauth,
79 email_rpc,
79 mail,
8080 })
8181 }
8282}
Modified lib/export/Cargo.toml lib/export/Cargo.toml +1 −1 View lib/export/Cargo.toml
@@ -12,7 +12,7 @@
1212redis = { workspace = true }
1313tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal"] }
1414auth = { workspace = true }
15token = { workspace = true }
15session = { workspace = true }
1616imaging = { workspace = true }
1717actix-web = { workspace = true }
1818http = "1.5.0"
Modified lib/git/src/handler/analysis/code_activity.rs lib/git/src/handler/analysis/code_activity.rs +1 −1 View lib/git/src/handler/analysis/code_activity.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/analysis/contributors.rs lib/git/src/handler/analysis/contributors.rs +1 −1 View lib/git/src/handler/analysis/contributors.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/analysis/languages.rs lib/git/src/handler/analysis/languages.rs +1 −1 View lib/git/src/handler/analysis/languages.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/analysis/languages_read.rs lib/git/src/handler/analysis/languages_read.rs +1 −1 View lib/git/src/handler/analysis/languages_read.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/archives/create.rs lib/git/src/handler/archives/create.rs +1 −1 View lib/git/src/handler/archives/create.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/archives/create_bundle.rs lib/git/src/handler/archives/create_bundle.rs +1 −1 View lib/git/src/handler/archives/create_bundle.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/archives/download.rs lib/git/src/handler/archives/download.rs +1 −1 View lib/git/src/handler/archives/download.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPathRev, resolve_reader};
Modified lib/git/src/handler/blobs/content.rs lib/git/src/handler/blobs/content.rs +1 −1 View lib/git/src/handler/blobs/content.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/blobs/list_lfs_pointers.rs lib/git/src/handler/blobs/list_lfs_pointers.rs +1 −1 View lib/git/src/handler/blobs/list_lfs_pointers.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/blobs/metadata.rs lib/git/src/handler/blobs/metadata.rs +1 −1 View lib/git/src/handler/blobs/metadata.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branch_protection/create_policy.rs lib/git/src/handler/branch_protection/create_policy.rs +1 −1 View lib/git/src/handler/branch_protection/create_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_repo_admin};
Modified lib/git/src/handler/branch_protection/delete_policy.rs lib/git/src/handler/branch_protection/delete_policy.rs +1 −1 View lib/git/src/handler/branch_protection/delete_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branch_protection/get_policy.rs lib/git/src/handler/branch_protection/get_policy.rs +1 −1 View lib/git/src/handler/branch_protection/get_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branch_protection/list_policies.rs lib/git/src/handler/branch_protection/list_policies.rs +1 −1 View lib/git/src/handler/branch_protection/list_policies.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_repo_admin};
Modified lib/git/src/handler/branch_protection/update_policy.rs lib/git/src/handler/branch_protection/update_policy.rs +1 −1 View lib/git/src/handler/branch_protection/update_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branches/create.rs lib/git/src/handler/branches/create.rs +1 −1 View lib/git/src/handler/branches/create.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branches/delete.rs lib/git/src/handler/branches/delete.rs +1 −1 View lib/git/src/handler/branches/delete.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branches/get.rs lib/git/src/handler/branches/get.rs +1 −1 View lib/git/src/handler/branches/get.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branches/list.rs lib/git/src/handler/branches/list.rs +1 −1 View lib/git/src/handler/branches/list.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branches/rename.rs lib/git/src/handler/branches/rename.rs +1 −1 View lib/git/src/handler/branches/rename.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/branches/set_default.rs lib/git/src/handler/branches/set_default.rs +1 −1 View lib/git/src/handler/branches/set_default.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/code_comments/create_code_comment.rs lib/git/src/handler/code_comments/create_code_comment.rs +1 −1 View lib/git/src/handler/code_comments/create_code_comment.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/code_comments/list_code_comments.rs lib/git/src/handler/code_comments/list_code_comments.rs +1 −1 View lib/git/src/handler/code_comments/list_code_comments.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/code_comments/modify.rs lib/git/src/handler/code_comments/modify.rs +1 −1 View lib/git/src/handler/code_comments/modify.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44use uuid::Uuid;
55
66use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/code_comments/resolve_code_comment.rs lib/git/src/handler/code_comments/resolve_code_comment.rs +1 −1 View lib/git/src/handler/code_comments/resolve_code_comment.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/commits/get.rs lib/git/src/handler/commits/get.rs +1 −1 View lib/git/src/handler/commits/get.rs
@@ -1,7 +1,7 @@
11use crate::rpcgit::commit::types::CommitInfo;
2use ::session::Session;
23use export::http::{Path, State};
34use export::rest::AppResponseData;
4use token::Session;
55
66use crate::errors::{ApiError, GitApiError};
77use crate::handler;
Modified lib/git/src/handler/commits/is_ancestor.rs lib/git/src/handler/commits/is_ancestor.rs +1 −1 View lib/git/src/handler/commits/is_ancestor.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44use serde::Serialize;
55
66use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/commits/list.rs lib/git/src/handler/commits/list.rs +1 −1 View lib/git/src/handler/commits/list.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/commits/list_commit_statuses.rs lib/git/src/handler/commits/list_commit_statuses.rs +1 −1 View lib/git/src/handler/commits/list_commit_statuses.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/commits/rev_parse.rs lib/git/src/handler/commits/rev_parse.rs +1 −1 View lib/git/src/handler/commits/rev_parse.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/commits/set_commit_status.rs lib/git/src/handler/commits/set_commit_status.rs +1 −1 View lib/git/src/handler/commits/set_commit_status.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/commits/stats.rs lib/git/src/handler/commits/stats.rs +1 −1 View lib/git/src/handler/commits/stats.rs
@@ -1,9 +1,9 @@
11use std::path::PathBuf;
22
33use crate::rpcgit::commit::types::CommitStats;
4use ::session::Session;
45use export::http::{Path, Query, State};
56use export::rest::AppResponseData;
6use token::Session;
77
88use crate::errors::{ApiError, GitApiError};
99use crate::handler;
Modified lib/git/src/handler/commits/sync_commit.rs lib/git/src/handler/commits/sync_commit.rs +1 −1 View lib/git/src/handler/commits/sync_commit.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44use serde::Serialize;
55
66use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/conflicts/detail.rs lib/git/src/handler/conflicts/detail.rs +1 −1 View lib/git/src/handler/conflicts/detail.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/conflicts/get_conflicts.rs lib/git/src/handler/conflicts/get_conflicts.rs +1 −1 View lib/git/src/handler/conflicts/get_conflicts.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/content/caller_signature.rs lib/git/src/handler/content/caller_signature.rs +1 −1 View lib/git/src/handler/content/caller_signature.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::AppResponseData;
3use token::Session;
44use time::OffsetDateTime;
55
66use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/content/commit_object.rs lib/git/src/handler/content/commit_object.rs +1 −1 View lib/git/src/handler/content/commit_object.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/content/write_blob.rs lib/git/src/handler/content/write_blob.rs +1 −1 View lib/git/src/handler/content/write_blob.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/content/write_tree_from_files.rs lib/git/src/handler/content/write_tree_from_files.rs +1 −1 View lib/git/src/handler/content/write_tree_from_files.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/diffs/for_commit.rs lib/git/src/handler/diffs/for_commit.rs +1 −1 View lib/git/src/handler/diffs/for_commit.rs
@@ -1,7 +1,7 @@
11use crate::rpcgit::diff::types::ChangedPath;
2use ::session::Session;
23use export::http::{Path, State};
34use export::rest::AppResponseData;
4use token::Session;
55
66use crate::errors::{ApiError, GitApiError};
77use crate::handler;
Modified lib/git/src/handler/diffs/get_diff.rs lib/git/src/handler/diffs/get_diff.rs +1 −1 View lib/git/src/handler/diffs/get_diff.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44use serde::Deserialize;
55
66use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/diffs/range_diff.rs lib/git/src/handler/diffs/range_diff.rs +1 −1 View lib/git/src/handler/diffs/range_diff.rs
@@ -1,7 +1,7 @@
11use crate::rpcgit::diff::types::RangeDiffSpec;
2use ::session::Session;
23use export::http::{Path, Query, State};
34use export::rest::AppResponseData;
4use token::Session;
55
66use crate::errors::{ApiError, GitApiError};
77use crate::handler;
Modified lib/git/src/handler/diffs/raw.rs lib/git/src/handler/diffs/raw.rs +1 −1 View lib/git/src/handler/diffs/raw.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/hooks/execute_script.rs lib/git/src/handler/hooks/execute_script.rs +1 −1 View lib/git/src/handler/hooks/execute_script.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/lfs/cleanup_unreferenced.rs lib/git/src/handler/lfs/cleanup_unreferenced.rs +1 −1 View lib/git/src/handler/lfs/cleanup_unreferenced.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/lfs/list_locks.rs lib/git/src/handler/lfs/list_locks.rs +1 −1 View lib/git/src/handler/lfs/list_locks.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, resolve_reader};
Modified lib/git/src/handler/lfs/lock.rs lib/git/src/handler/lfs/lock.rs +1 −1 View lib/git/src/handler/lfs/lock.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/lfs/mod.rs lib/git/src/handler/lfs/mod.rs +1 −1 View lib/git/src/handler/lfs/mod.rs
@@ -1,4 +1,4 @@
1use token::Session;
1use ::session::Session;
22
33use crate::errors::ApiError;
44use crate::handler::{require_repo_admin, require_writer};
Modified lib/git/src/handler/lfs/unlock.rs lib/git/src/handler/lfs/unlock.rs +1 −1 View lib/git/src/handler/lfs/unlock.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, lfs};
Modified lib/git/src/handler/lfs/unlock_by_id.rs lib/git/src/handler/lfs/unlock_by_id.rs +1 −1 View lib/git/src/handler/lfs/unlock_by_id.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::lfs;
Modified lib/git/src/handler/lfs/verify_locks.rs lib/git/src/handler/lfs/verify_locks.rs +1 −1 View lib/git/src/handler/lfs/verify_locks.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/maintenance/fsck.rs lib/git/src/handler/maintenance/fsck.rs +1 −1 View lib/git/src/handler/maintenance/fsck.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/maintenance/prune.rs lib/git/src/handler/maintenance/prune.rs +1 −1 View lib/git/src/handler/maintenance/prune.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/packs/ingest.rs lib/git/src/handler/packs/ingest.rs +1 −1 View lib/git/src/handler/packs/ingest.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Bytes, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/packs/repack.rs lib/git/src/handler/packs/repack.rs +1 −1 View lib/git/src/handler/packs/repack.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/packs/stats.rs lib/git/src/handler/packs/stats.rs +1 −1 View lib/git/src/handler/packs/stats.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, resolve_reader};
Modified lib/git/src/handler/patches/apply.rs lib/git/src/handler/patches/apply.rs +1 −1 View lib/git/src/handler/patches/apply.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/patches/generate.rs lib/git/src/handler/patches/generate.rs +1 −1 View lib/git/src/handler/patches/generate.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/patches/parse.rs lib/git/src/handler/patches/parse.rs +1 −1 View lib/git/src/handler/patches/parse.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/refs/branches.rs lib/git/src/handler/refs/branches.rs +1 −1 View lib/git/src/handler/refs/branches.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/refs/delete.rs lib/git/src/handler/refs/delete.rs +1 −1 View lib/git/src/handler/refs/delete.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/refs/filtered.rs lib/git/src/handler/refs/filtered.rs +1 −1 View lib/git/src/handler/refs/filtered.rs
@@ -1,7 +1,7 @@
11use crate::rpcgit::refs::types::RefInfo;
2use ::session::Session;
23use export::http::{Path, Query, State};
34use export::rest::AppResponseData;
4use token::Session;
55
66use crate::errors::{ApiError, GitApiError};
77use crate::handler;
Modified lib/git/src/handler/refs/get.rs lib/git/src/handler/refs/get.rs +1 −1 View lib/git/src/handler/refs/get.rs
@@ -1,7 +1,7 @@
11use crate::rpcgit::refs::types::RefInfo;
2use ::session::Session;
23use export::http::{Path, State};
34use export::rest::AppResponseData;
4use token::Session;
55
66use crate::errors::{ApiError, GitApiError};
77use crate::handler;
Modified lib/git/src/handler/refs/head.rs lib/git/src/handler/refs/head.rs +1 −1 View lib/git/src/handler/refs/head.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/refs/is_object_in_ref.rs lib/git/src/handler/refs/is_object_in_ref.rs +1 −1 View lib/git/src/handler/refs/is_object_in_ref.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44use serde::Serialize;
55
66use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/refs/list.rs lib/git/src/handler/refs/list.rs +1 −1 View lib/git/src/handler/refs/list.rs
@@ -1,7 +1,7 @@
11use crate::rpcgit::refs::types::RefInfo;
2use ::session::Session;
23use export::http::{Path, State};
34use export::rest::AppResponseData;
4use token::Session;
55
66use crate::errors::{ApiError, GitApiError};
77use crate::handler;
Modified lib/git/src/handler/refs/resolve.rs lib/git/src/handler/refs/resolve.rs +1 −1 View lib/git/src/handler/refs/resolve.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/refs/update.rs lib/git/src/handler/refs/update.rs +1 −1 View lib/git/src/handler/refs/update.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44use serde::{Deserialize, Serialize};
55
66use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/releases/create_release.rs lib/git/src/handler/releases/create_release.rs +1 −1 View lib/git/src/handler/releases/create_release.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/releases/delete_release.rs lib/git/src/handler/releases/delete_release.rs +1 −1 View lib/git/src/handler/releases/delete_release.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{require_repo_admin, require_writer};
Modified lib/git/src/handler/releases/get_release.rs lib/git/src/handler/releases/get_release.rs +1 −1 View lib/git/src/handler/releases/get_release.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/releases/list_releases.rs lib/git/src/handler/releases/list_releases.rs +1 −1 View lib/git/src/handler/releases/list_releases.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/releases/update_release.rs lib/git/src/handler/releases/update_release.rs +1 −1 View lib/git/src/handler/releases/update_release.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{require_repo_admin, require_writer};
Modified lib/git/src/handler/remotes/add.rs lib/git/src/handler/remotes/add.rs +1 −1 View lib/git/src/handler/remotes/add.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/remotes/clone_import.rs lib/git/src/handler/remotes/clone_import.rs +1 −1 View lib/git/src/handler/remotes/clone_import.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/remotes/fetch.rs lib/git/src/handler/remotes/fetch.rs +1 −1 View lib/git/src/handler/remotes/fetch.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/remotes/list.rs lib/git/src/handler/remotes/list.rs +1 −1 View lib/git/src/handler/remotes/list.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, ensure_read_access};
Modified lib/git/src/handler/remotes/push.rs lib/git/src/handler/remotes/push.rs +1 −1 View lib/git/src/handler/remotes/push.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_writer};
Modified lib/git/src/handler/remotes/remove.rs lib/git/src/handler/remotes/remove.rs +1 −1 View lib/git/src/handler/remotes/remove.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/repos/archive.rs lib/git/src/handler/repos/archive.rs +1 −1 View lib/git/src/handler/repos/archive.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, ensure_caller};
Modified lib/git/src/handler/repos/create.rs lib/git/src/handler/repos/create.rs +1 −1 View lib/git/src/handler/repos/create.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/repos/get.rs lib/git/src/handler/repos/get.rs +1 −1 View lib/git/src/handler/repos/get.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, resolve_reader};
Modified lib/git/src/handler/repos/list.rs lib/git/src/handler/repos/list.rs +1 −1 View lib/git/src/handler/repos/list.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::service::GitService;
Modified lib/git/src/handler/repos/update.rs lib/git/src/handler/repos/update.rs +1 −1 View lib/git/src/handler/repos/update.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, ensure_caller};
Modified lib/git/src/handler/signatures/verify_commit.rs lib/git/src/handler/signatures/verify_commit.rs +1 −1 View lib/git/src/handler/signatures/verify_commit.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/signatures/verify_tag.rs lib/git/src/handler/signatures/verify_tag.rs +1 −1 View lib/git/src/handler/signatures/verify_tag.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/submodules/list.rs lib/git/src/handler/submodules/list.rs +1 −1 View lib/git/src/handler/submodules/list.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/submodules/resolve.rs lib/git/src/handler/submodules/resolve.rs +1 −1 View lib/git/src/handler/submodules/resolve.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/tag_protection/create_policy.rs lib/git/src/handler/tag_protection/create_policy.rs +1 −1 View lib/git/src/handler/tag_protection/create_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_repo_admin};
Modified lib/git/src/handler/tag_protection/delete_policy.rs lib/git/src/handler/tag_protection/delete_policy.rs +1 −1 View lib/git/src/handler/tag_protection/delete_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/tag_protection/get_policy.rs lib/git/src/handler/tag_protection/get_policy.rs +1 −1 View lib/git/src/handler/tag_protection/get_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/tag_protection/list_policies.rs lib/git/src/handler/tag_protection/list_policies.rs +1 −1 View lib/git/src/handler/tag_protection/list_policies.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler::{RepoPath, require_repo_admin};
Modified lib/git/src/handler/tag_protection/update_policy.rs lib/git/src/handler/tag_protection/update_policy.rs +1 −1 View lib/git/src/handler/tag_protection/update_policy.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/tags/create.rs lib/git/src/handler/tags/create.rs +1 −1 View lib/git/src/handler/tags/create.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/tags/delete.rs lib/git/src/handler/tags/delete.rs +1 −1 View lib/git/src/handler/tags/delete.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/tags/get.rs lib/git/src/handler/tags/get.rs +1 −1 View lib/git/src/handler/tags/get.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/tags/list.rs lib/git/src/handler/tags/list.rs +1 −1 View lib/git/src/handler/tags/list.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/trees/read.rs lib/git/src/handler/trees/read.rs +1 −1 View lib/git/src/handler/trees/read.rs
@@ -1,8 +1,8 @@
11use std::path::PathBuf;
22
3use ::session::Session;
34use export::http::{Path, Query, State};
45use export::rest::AppResponseData;
5use token::Session;
66use serde::Deserialize;
77
88use crate::errors::{ApiError, GitApiError};
Modified lib/git/src/handler/blame.rs lib/git/src/handler/blame.rs +1 −1 View lib/git/src/handler/blame.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/path_log.rs lib/git/src/handler/path_log.rs +1 −1 View lib/git/src/handler/path_log.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::{ApiError, GitApiError};
66use crate::handler;
Modified lib/git/src/handler/share.rs lib/git/src/handler/share.rs +1 −1 View lib/git/src/handler/share.rs
@@ -1,9 +1,9 @@
11use std::future::Future;
22use std::pin::Pin;
33
4use ::session::Session;
45use actix_web::dev::Payload;
56use actix_web::{FromRequest, HttpRequest};
6use token::Session;
77use serde::Deserialize;
88use utoipa::IntoParams;
99
Modified lib/git/src/handler/stars.rs lib/git/src/handler/stars.rs +1 −1 View lib/git/src/handler/stars.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44use serde::Deserialize;
55use utoipa::IntoParams;
66
Modified lib/git/src/handler/topics.rs lib/git/src/handler/topics.rs +1 −1 View lib/git/src/handler/topics.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44use serde::{Deserialize, Serialize};
55use utoipa::IntoParams;
66
Modified lib/git/src/handler/watches.rs lib/git/src/handler/watches.rs +1 −1 View lib/git/src/handler/watches.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Json, Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44use models::common::watch_mode::WatchMode;
55use serde::Deserialize;
66use utoipa::IntoParams;
Modified lib/git/src/handler/whitelists.rs lib/git/src/handler/whitelists.rs +1 −1 View lib/git/src/handler/whitelists.rs
@@ -4,7 +4,7 @@
44use utoipa::IntoParams;
55use uuid::Uuid;
66
7use token::Session;
7use ::session::Session;
88
99use crate::errors::{ApiError, GitApiError};
1010use crate::handler;
Modified lib/git/src/share/access.rs lib/git/src/share/access.rs +3 −24 View lib/git/src/share/access.rs
@@ -47,31 +47,10 @@
4747}
4848
4949pub async fn verify_access_key(
50 svc: &GitService,
51 token: &str,
50 _svc: &GitService,
51 _token: &str,
5252) -> Result<Option<(i64, AccessKeyScope)>, GitError> {
53 let Some(client) = svc.state.kenauth.as_ref() else {
54 return Err(GitError::Internal(
55 "kenoauth is not configured for access key verification".into(),
56 ));
57 };
58 match client.verify_access_key(token, Vec::new()).await {
59 Ok(Some(principal)) => {
60 let write = principal.scopes.iter().any(|scope| *scope == 12);
61 Ok(Some((
62 principal.user_id,
63 if write {
64 AccessKeyScope::Write
65 } else {
66 AccessKeyScope::Read
67 },
68 )))
69 }
70 Ok(None) => Ok(None),
71 Err(error) => Err(GitError::Internal(format!(
72 "access key verification failed: {error}"
73 ))),
74 }
53 Ok(None)
7554}
7655
7756/// HTTP write-path auth: token must be valid AND the resolved `uid` must
Modified lib/git/Cargo.toml lib/git/Cargo.toml +1 −1 View lib/git/Cargo.toml
@@ -29,7 +29,7 @@
2929tracing = { workspace = true }
3030flate2 = { workspace = true }
3131bytes = { workspace = true }
32token = { workspace = true }
32session = { workspace = true }
3333utoipa = { workspace = true }
3434maud = { workspace = true }
3535pulldown-cmark = { workspace = true }
Modified lib/issues/src/handlers/attachments/create_attachment.rs lib/issues/src/handlers/attachments/create_attachment.rs +2 −2 View lib/issues/src/handlers/attachments/create_attachment.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Json, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55
66use crate::errors::ApiError;
77use crate::services::attachments::{CreateIssueAttachmentCmd, IssueUploadIntentDto};
Modified lib/issues/src/handlers/attachments/delete_attachment.rs lib/issues/src/handlers/attachments/delete_attachment.rs +2 −2 View lib/issues/src/handlers/attachments/delete_attachment.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/issues/src/handlers/attachments/download_attachment.rs lib/issues/src/handlers/attachments/download_attachment.rs +2 −2 View lib/issues/src/handlers/attachments/download_attachment.rs
@@ -1,8 +1,8 @@
1use ::session::Session;
2use ::session::share::session;
13use actix_web::http::header;
24use export::http::{Path, Response, State};
35use export::rest::{AppResponseData, NoData};
4use token::Session;
5use token::share::session;
66use uuid::Uuid;
77
88use crate::errors::ApiError;
Modified lib/issues/src/handlers/attachments/finalize_attachment.rs lib/issues/src/handlers/attachments/finalize_attachment.rs +2 −2 View lib/issues/src/handlers/attachments/finalize_attachment.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55use uuid::Uuid;
66
77use crate::errors::ApiError;
Modified lib/issues/src/handlers/attachments/list_attachments.rs lib/issues/src/handlers/attachments/list_attachments.rs +2 −2 View lib/issues/src/handlers/attachments/list_attachments.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
2use ::session::share::session;
13use export::http::{Path, State};
24use export::rest::{AppResponseData, NoData};
3use token::Session;
4use token::share::session;
55
66use crate::errors::ApiError;
77use crate::services::attachments::IssueAttachmentDto;
Modified lib/issues/src/handlers/boards/create_board.rs lib/issues/src/handlers/boards/create_board.rs +2 −2 View lib/issues/src/handlers/boards/create_board.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::boards::{BoardDto, CreateBoardCmd};
77use crate::services::service::IssueService;
8use ::session::share::session;
89use space::services::spaces::SpaceNamePath;
9use token::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/issues/src/handlers/boards/delete_board.rs lib/issues/src/handlers/boards/delete_board.rs +2 −2 View lib/issues/src/handlers/boards/delete_board.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::boards::BoardPath;
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/issues/src/handlers/boards/get_board.rs lib/issues/src/handlers/boards/get_board.rs +2 −2 View lib/issues/src/handlers/boards/get_board.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::boards::{BoardDto, BoardPath};
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/issues/src/handlers/boards/list_boards.rs lib/issues/src/handlers/boards/list_boards.rs +2 −2 View lib/issues/src/handlers/boards/list_boards.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::boards::{BoardPage, ListBoardQuery};
77use crate::services::service::IssueService;
8use ::session::share::session;
89use space::services::spaces::SpaceNamePath;
9use token::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/issues/src/handlers/boards/update_board.rs lib/issues/src/handlers/boards/update_board.rs +2 −2 View lib/issues/src/handlers/boards/update_board.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::boards::{BoardDto, BoardPath, UpdateBoardCmd};
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 patch,
Modified lib/issues/src/handlers/comments/create_comment.rs lib/issues/src/handlers/comments/create_comment.rs +2 −2 View lib/issues/src/handlers/comments/create_comment.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::comments::{CommentDto, CreateCommentCmd};
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/issues/src/handlers/comments/delete_comment.rs lib/issues/src/handlers/comments/delete_comment.rs +2 −2 View lib/issues/src/handlers/comments/delete_comment.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::comments::CommentPath;
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/issues/src/handlers/comments/get_comment.rs lib/issues/src/handlers/comments/get_comment.rs +2 −2 View lib/issues/src/handlers/comments/get_comment.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::comments::{CommentDto, CommentPath};
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/issues/src/handlers/comments/list_comments.rs lib/issues/src/handlers/comments/list_comments.rs +2 −2 View lib/issues/src/handlers/comments/list_comments.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::comments::{CommentPage, ListCommentQuery};
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/issues/src/handlers/comments/list_comments_tree.rs lib/issues/src/handlers/comments/list_comments_tree.rs +2 −2 View lib/issues/src/handlers/comments/list_comments_tree.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::comments::CommentTreeNode;
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/issues/src/handlers/comments/update_comment.rs lib/issues/src/handlers/comments/update_comment.rs +2 −2 View lib/issues/src/handlers/comments/update_comment.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::comments::{CommentDto, CommentPath, UpdateCommentCmd};
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 patch,
Modified lib/issues/src/handlers/content_history/list_content_history.rs lib/issues/src/handlers/content_history/list_content_history.rs +2 −2 View lib/issues/src/handlers/content_history/list_content_history.rs
@@ -1,13 +1,13 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::content_history::{
77 ContentHistoryPage, ContentHistoryPath, ListContentHistoryQuery,
88};
99use crate::services::service::IssueService;
10use token::share::session;
10use ::session::share::session;
1111
1212#[utoipa::path(
1313 get,
Modified lib/issues/src/handlers/dependencies/create_dependency.rs lib/issues/src/handlers/dependencies/create_dependency.rs +2 −2 View lib/issues/src/handlers/dependencies/create_dependency.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dependencies::{CreateDependencyCmd, DependencyDto};
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/issues/src/handlers/dependencies/delete_dependency.rs lib/issues/src/handlers/dependencies/delete_dependency.rs +2 −2 View lib/issues/src/handlers/dependencies/delete_dependency.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dependencies::DependencyPath;
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/issues/src/handlers/dependencies/list_dependencies.rs lib/issues/src/handlers/dependencies/list_dependencies.rs +2 −2 View lib/issues/src/handlers/dependencies/list_dependencies.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dependencies::DependencyDto;
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/issues/src/handlers/dependencies/list_dependents.rs lib/issues/src/handlers/dependencies/list_dependents.rs +2 −2 View lib/issues/src/handlers/dependencies/list_dependents.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dependencies::DependencyDto;
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/issues/src/handlers/events/list_events.rs lib/issues/src/handlers/events/list_events.rs +2 −2 View lib/issues/src/handlers/events/list_events.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::events::{EventPage, EventPath, ListEventQuery};
77use crate::services::service::IssueService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/issues/src/handlers/issue_users/list_issue_users.rs lib/issues/src/handlers/issue_users/list_issue_users.rs +2 −2 View lib/issues/src/handlers/issue_users/list_issue_users.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::issue_users::{IssueUserPage, ListIssueUserQuery};
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/issues/src/handlers/issue_users/mark_issue_read.rs lib/issues/src/handlers/issue_users/mark_issue_read.rs +2 −2 View lib/issues/src/handlers/issue_users/mark_issue_read.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::issue_users::{IssueUserDto, UpdateIssueUserCmd};
77use crate::services::issues::IssuePath;
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
1212pub struct MarkIssueReadCmd {
Modified lib/issues/src/handlers/issues/bulk_issues.rs lib/issues/src/handlers/issues/bulk_issues.rs +2 −2 View lib/issues/src/handlers/issues/bulk_issues.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::boards::BoardPath;
77use crate::services::issues::{BulkIssuesCmd, BulkResultDto};
88use crate::services::service::IssueService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/issues/src/services/service.rs lib/issues/src/services/service.rs +2 −2 View lib/issues/src/services/service.rs
@@ -289,12 +289,12 @@
289289 text: &str,
290290 html: &str,
291291 ) -> Result<(), IssueError> {
292 let Some(client) = self.state.email_rpc.as_ref() else {
292 let Some(client) = self.state.mail.as_ref() else {
293293 tracing::warn!(to, "email rpc disabled; skipping issue mail");
294294 return Ok(());
295295 };
296296 client
297 .send_mail(to, subject, text, html)
297 .send_mail(to, subject, text, html, None)
298298 .await
299299 .map_err(|error| IssueError::Internal(format!("email send failed: {error}")))
300300 }
Modified lib/issues/src/share/guard.rs lib/issues/src/share/guard.rs +1 −1 View lib/issues/src/share/guard.rs
@@ -1 +1 @@
1pub use token::share::guard::session_guard as issue_guard;
1pub use ::session::share::guard::session_guard as issue_guard;
Modified lib/issues/Cargo.toml lib/issues/Cargo.toml +1 −1 View lib/issues/Cargo.toml
@@ -12,7 +12,7 @@
1212i18n = { workspace = true }
1313models = { workspace = true }
1414queue = { workspace = true }
15token = { workspace = true }
15session = { workspace = true }
1616space = { workspace = true }
1717actix-web = { workspace = true }
1818http = { workspace = true }
Modified lib/models/src/users/mod.rs lib/models/src/users/mod.rs +0 −2 View lib/models/src/users/mod.rs
@@ -1,9 +1,7 @@
11pub const DATABASE: &str = "user";
22
33pub mod access_scope;
4pub mod service_token_revocations;
54pub mod user;
6pub mod user_access_tokens;
75pub mod user_agreement_acceptances;
86pub mod user_blocks;
97pub mod user_events;
Modified lib/models/src/users/users.rs lib/models/src/users/users.rs +0 −2 View lib/models/src/users/users.rs
@@ -55,8 +55,6 @@
5555 pub deletion_requested_at: Option<DateTimeUtc>,
5656
5757 #[sea_orm(has_many)]
58 pub access_tokens: HasMany<super::user_access_tokens::Entity>,
59 #[sea_orm(has_many)]
6058 pub ssh_keys: HasMany<super::user_ssh_keys::Entity>,
6159 #[sea_orm(has_many)]
6260 pub events: HasMany<super::user_events::Entity>,
Modified lib/pulls/src/handlers/inbox.rs lib/pulls/src/handlers/inbox.rs +1 −1 View lib/pulls/src/handlers/inbox.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::AppResponseData;
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::inbox::{InboxPage, InboxQuery};
Modified lib/pulls/src/services/service.rs lib/pulls/src/services/service.rs +1 −1 View lib/pulls/src/services/service.rs
@@ -1,3 +1,4 @@
1use ::session::Session;
12use config::AppConfig;
23use export::AppState;
34use git::service::GitService;
@@ -7,7 +8,6 @@
78use sea_orm::{
89 ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter,
910};
10use token::Session;
1111use uuid::Uuid;
1212
1313use crate::errors::PullError;
Modified lib/pulls/src/share/lookup.rs lib/pulls/src/share/lookup.rs +1 −1 View lib/pulls/src/share/lookup.rs
@@ -1,8 +1,8 @@
1use ::session::Session;
12use git::context::facade::GitContext;
23use git::share::access;
34use models::pull_request::pull_requests;
45use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
5use token::Session;
66use uuid::Uuid;
77
88use crate::errors::PullError;
Modified lib/pulls/Cargo.toml lib/pulls/Cargo.toml +1 −1 View lib/pulls/Cargo.toml
@@ -10,7 +10,7 @@
1010issues = { workspace = true }
1111models = { workspace = true }
1212queue = { workspace = true }
13token = { workspace = true }
13session = { workspace = true }
1414space = { workspace = true }
1515actix-web = { workspace = true }
1616sea-orm = { workspace = true }
Modified lib/queue/src/lib.rs lib/queue/src/lib.rs +2 −0 View lib/queue/src/lib.rs
@@ -1,6 +1,7 @@
11#![recursion_limit = "512"]
22
33pub mod conn;
4pub mod consumer;
45pub mod envelope;
56pub mod error;
67pub mod publisher;
@@ -8,6 +9,7 @@
89pub mod subject;
910
1011pub use conn::{DEFAULT_MAX_MESSAGE_BYTES, RocketMqConn};
12pub use consumer::{Consumer, ConsumerConfig, MessageHandler};
1113pub use envelope::{DeliveryClass, EVENT_PREFIX, Envelope, Labels, SCHEMA_VERSION};
1214pub use error::{QueueError, QueueResult};
1315pub use publisher::Publisher;
Modified lib/session/src/error.rs lib/session/src/error.rs +39 −1 View lib/session/src/error.rs
@@ -1,6 +1,8 @@
11use std::error::Error;
22use std::fmt::{self, Display, Formatter};
33
4use actix_web::http::StatusCode;
5use actix_web::{HttpResponse, ResponseError};
46use cache::CacheError;
57use cache::redis::RedisError;
68
@@ -15,6 +17,7 @@
1517 source: serde_json::Error,
1618 },
1719 Purged,
20 Unauthorized,
1821 UpdateConflict {
1922 key: String,
2023 },
@@ -65,6 +68,7 @@
6568 write!(f, "failed to deserialize session field `{key}`: {source}")
6669 }
6770 Self::Purged => f.write_str("session record has been purged"),
71 Self::Unauthorized => f.write_str("authentication required"),
6872 Self::UpdateConflict { key } => {
6973 write!(
7074 f,
@@ -84,9 +88,43 @@
8488 Self::Serialize { source, .. } | Self::Deserialize { source, .. } => Some(source),
8589 Self::Store(source) => Some(source),
8690 Self::Backend(source) => Some(source),
87 Self::Purged | Self::UpdateConflict { .. } | Self::Config(_) => None,
91 Self::Purged | Self::Unauthorized | Self::UpdateConflict { .. } | Self::Config(_) => {
92 None
93 }
94 }
95 }
96}
97
98impl ResponseError for SessionError {
99 fn status_code(&self) -> StatusCode {
100 match self {
101 Self::Unauthorized | Self::Purged => StatusCode::UNAUTHORIZED,
102 _ => StatusCode::INTERNAL_SERVER_ERROR,
88103 }
89104 }
105
106 fn error_response(&self) -> HttpResponse {
107 let status = self.status_code();
108 let error_code = match self {
109 Self::Unauthorized => "unauthenticated",
110 Self::Purged => "session_revoked",
111 _ => "internal",
112 };
113 let message = if status.is_server_error() {
114 "internal server error".to_owned()
115 } else {
116 self.to_string()
117 };
118 HttpResponse::build(status).json(serde_json::json!({
119 "code": status.as_u16(),
120 "message": message,
121 "data": null,
122 "error": null,
123 "error_code": error_code,
124 "request_id": null,
125 "log_id": null,
126 }))
127 }
90128}
91129
92130impl From<CacheError> for SessionError {
Modified lib/session/src/lib.rs lib/session/src/lib.rs +16 −2 View lib/session/src/lib.rs
@@ -1,18 +1,32 @@
1pub mod cookie;
12pub mod error;
23pub mod extract;
4pub mod guard;
35pub mod key;
46pub mod middleware;
57pub mod redis;
68pub mod state;
79pub mod store;
810
11pub use cookie::{clear_session_cookie, read_cookie, session_cookie};
912pub use error::SessionError;
1013pub use extract::{REQUEST_ID_HEADER, REQUEST_ID_MAX_LEN, RequestId, validate_request_id};
14pub use guard::{require_uid, session_guard};
1115pub use key::{MAX_SESSION_KEY_LEN, SESSION_KEY_LEN, SessionKey};
1216pub use middleware::SessionMiddleware;
1317pub use redis::RedisStore;
1418pub use state::{
15 SESSION_CLIENT_ID, SESSION_CLIENT_IP, SESSION_SECURITY_VERSION, SESSION_USER_AGENT,
16 SESSION_USER_ID, Session, SessionStatus,
19 SESSION_AUTH_SESSION_ID, SESSION_CLIENT_ID, SESSION_CLIENT_IP, SESSION_MFA_VERIFIED,
20 SESSION_SECURITY_VERSION, SESSION_USER_AGENT, SESSION_USER_ID, Session, SessionStatus,
1721};
1822pub use store::{SessionDiff, SessionState, SessionStore, generate_session_key};
23
24pub mod share {
25 pub mod guard {
26 pub use crate::guard::session_guard;
27 }
28
29 pub mod session {
30 pub use crate::guard::require_uid;
31 }
32}
Modified lib/session/src/middleware.rs lib/session/src/middleware.rs +41 −62 View lib/session/src/middleware.rs
@@ -96,13 +96,16 @@
9696 let storage_backend = Rc::clone(&self.storage_backend);
9797 let configuration = Rc::clone(&self.config);
9898 Box::pin(async move {
99 let session_key = req
99 let provided_key = req
100100 .cookie(&configuration.cookie_name)
101101 .and_then(|cookie| SessionKey::try_from(cookie.value().to_owned()).ok());
102 let (session_key, session_state) =
103 load_session_state(session_key, storage_backend.as_ref()).await?;
102 let (session_key, loaded) =
103 load_session_state(provided_key.clone(), storage_backend.as_ref()).await?;
104 let remaining_ttl = loaded.as_ref().map(|(_, ttl)| *ttl);
105 let session_state = loaded.map(|(state, _)| state).unwrap_or_default();
104106
105107 let session = Session::from_state(session_state);
108 let previous_user_id = session.uid();
106109 req.extensions_mut().insert(session.clone());
107110
108111 record_client(&session, req.request(), configuration.trust_proxy);
@@ -135,6 +138,7 @@
135138 .unwrap_or(session);
136139
137140 let (status, state) = session.snapshot();
141 let user_id = session.uid();
138142 let ttl = Duration::seconds(session_ttl(&configuration, &session));
139143
140144 match session_key {
@@ -142,12 +146,14 @@
142146 if has_identity(&state) {
143147 let session_key = storage_backend.save(state, &ttl).await.map_err(e500)?;
144148 set_session_cookie(res.response_mut(), &configuration, session_key, ttl)?;
149 } else if provided_key.is_some() {
150 clear_session_cookie(res.response_mut(), &configuration, ttl)?;
145151 }
146152 }
147153 Some(session_key) => match status {
148154 SessionStatus::Changed => {
149155 match storage_backend
150 .update(session_key, session.diff(), &ttl)
156 .update(session_key, session.diff(), &ttl, previous_user_id, user_id)
151157 .await
152158 {
153159 Ok(session_key) => {
@@ -164,7 +170,7 @@
164170 }
165171 SessionStatus::Renewed => {
166172 match storage_backend
167 .rotate(session_key, session.diff(), &ttl)
173 .rotate(session_key, session.diff(), &ttl, previous_user_id, user_id)
168174 .await
169175 {
170176 Ok(Some(new_session_key)) => {
@@ -183,10 +189,34 @@
183189 }
184190 }
185191 SessionStatus::Purged => {
186 storage_backend.delete(&session_key).await.map_err(e500)?;
192 storage_backend
193 .delete(&session_key, previous_user_id)
194 .await
195 .map_err(e500)?;
187196 clear_session_cookie(res.response_mut(), &configuration, ttl)?;
188197 }
189 SessionStatus::UnChanged => {}
198 SessionStatus::UnChanged => {
199 let remaining = remaining_ttl.map(|ttl| ttl.whole_seconds()).unwrap_or(0);
200 if remaining < ttl.whole_seconds() / 2 {
201 match storage_backend
202 .update_ttl(&session_key, &ttl, user_id)
203 .await
204 {
205 Ok(()) => {
206 set_session_cookie(
207 res.response_mut(),
208 &configuration,
209 session_key,
210 ttl,
211 )?;
212 }
213 Err(SessionError::Purged) => {
214 clear_session_cookie(res.response_mut(), &configuration, ttl)?;
215 }
216 Err(error) => return Err(e500(error)),
217 }
218 }
219 }
190220 },
191221 }
192222
@@ -243,13 +273,13 @@
243273async fn load_session_state<Store: SessionStore>(
244274 session_key: Option<SessionKey>,
245275 storage_backend: &Store,
246) -> Result<(Option<SessionKey>, SessionState), actix_web::Error> {
276) -> Result<(Option<SessionKey>, Option<(SessionState, Duration)>), actix_web::Error> {
247277 match session_key {
248278 Some(session_key) => match storage_backend.load(&session_key).await.map_err(e500)? {
249 Some(session_state) => Ok((Some(session_key), session_state)),
250 None => Ok((None, SessionState::new())),
279 Some(loaded) => Ok((Some(session_key), Some(loaded))),
280 None => Ok((None, None)),
251281 },
252 None => Ok((None, SessionState::new())),
282 None => Ok((None, None)),
253283 }
254284}
255285
@@ -296,55 +326,4 @@
296326 cookie.set_domain(domain.clone());
297327 }
298328 cookie
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 fn config(secure: bool, same_site: SameSite) -> SessionConfig {
306 SessionConfig {
307 cookie_name: "session".into(),
308 max_age: 3600,
309 anonymous_max_age: 300,
310 path: Some("/".into()),
311 domain: None,
312 secure,
313 same_site,
314 trust_proxy: false,
315 }
316 }
317
318 #[test]
319 fn session_cookie_is_always_httponly() {
320 let cookie = session_cookie(
321 &config(true, SameSite::Lax),
322 "key".into(),
323 Duration::days(1),
324 );
325 assert_eq!(cookie.http_only(), Some(true));
326 }
327
328 #[test]
329 fn same_site_none_forces_secure() {
330 let cookie = session_cookie(
331 &config(false, SameSite::None),
332 "key".into(),
333 Duration::days(1),
334 );
335 assert_eq!(cookie.secure(), Some(true));
336 // Lax 下 secure 跟随配置(这里为 false),强制只发生在 SameSite=None。
337 let cookie = session_cookie(
338 &config(false, SameSite::Lax),
339 "key".into(),
340 Duration::days(1),
341 );
342 assert_eq!(cookie.secure(), Some(false));
343 let cookie = session_cookie(
344 &config(true, SameSite::Lax),
345 "key".into(),
346 Duration::days(1),
347 );
348 assert_eq!(cookie.secure(), Some(true));
349 }
350329}
Modified lib/session/src/redis.rs lib/session/src/redis.rs +166 −22 View lib/session/src/redis.rs
@@ -1,7 +1,7 @@
11use std::sync::LazyLock;
22
33use actix_web::cookie::time::Duration;
4use cache::redis::{AsyncCommands, Script, ScriptInvocation};
4use cache::redis::{Script, ScriptInvocation};
55use cache::{Cache, CacheConnection};
66
77use config::redis::RedisConfig;
@@ -11,6 +11,7 @@
1111use crate::store::{SessionDiff, SessionState, SessionStore, generate_session_key};
1212
1313const KEY_PREFIX: &str = "session";
14const USER_BUCKET_PREFIX: &str = "user:session";
1415
1516const SAVE_ATTEMPTS: usize = 3;
1617
@@ -25,7 +26,10 @@
2526 redis.call('DEL', KEYS[1])
2627 return {}
2728end
28return redis.call('HGETALL', KEYS[1])
29local ttl = redis.call('TTL', KEYS[1])
30local values = redis.call('HGETALL', KEYS[1])
31table.insert(values, 1, tostring(ttl))
32return values
2933"#,
3034 )
3135});
@@ -36,12 +40,16 @@
3640if redis.call('EXISTS', KEYS[1]) == 1 then
3741 return 0
3842end
39for index = 2, #ARGV, 2 do
43for index = 5, #ARGV, 2 do
4044 redis.call('HSET', KEYS[1], ARGV[index], ARGV[index + 1])
4145end
4246if redis.call('EXPIRE', KEYS[1], ARGV[1]) == 0 then
4347 return -1
4448end
49if ARGV[4] == '1' then
50 redis.call('SADD', KEYS[2], ARGV[3])
51 redis.call('EXPIRE', KEYS[2], ARGV[2])
52end
4553return 1
4654"#,
4755 )
@@ -57,8 +65,8 @@
5765 end
5866 return 0
5967end
60local index = 3
61local set_count = tonumber(ARGV[2])
68local index = 7
69local set_count = tonumber(ARGV[6])
6270for _ = 1, set_count do
6371 redis.call('HSET', KEYS[1], ARGV[index], ARGV[index + 1])
6472 index = index + 2
@@ -70,6 +78,13 @@
7078 index = index + 1
7179end
7280redis.call('EXPIRE', KEYS[1], ARGV[1])
81if ARGV[4] == '1' then
82 redis.call('SREM', KEYS[2], ARGV[3])
83end
84if ARGV[5] == '1' then
85 redis.call('SADD', KEYS[3], ARGV[3])
86 redis.call('EXPIRE', KEYS[3], ARGV[2])
87end
7388return 1
7489"#,
7590 )
@@ -88,8 +103,8 @@
88103if redis.call('RENAMENX', KEYS[1], KEYS[2]) == 0 then
89104 return -1
90105end
91local index = 3
92local set_count = tonumber(ARGV[2])
106local index = 8
107local set_count = tonumber(ARGV[7])
93108for _ = 1, set_count do
94109 redis.call('HSET', KEYS[2], ARGV[index], ARGV[index + 1])
95110 index = index + 2
@@ -103,11 +118,58 @@
103118if redis.call('EXPIRE', KEYS[2], ARGV[1]) == 0 then
104119 return 2
105120end
121if ARGV[5] == '1' then
122 redis.call('SREM', KEYS[3], ARGV[3])
123end
124if ARGV[6] == '1' then
125 redis.call('SADD', KEYS[4], ARGV[4])
126 redis.call('EXPIRE', KEYS[4], ARGV[2])
127end
128return 1
129"#,
130 )
131});
132
133static UPDATE_TTL_SCRIPT: LazyLock<Script> = LazyLock::new(|| {
134 Script::new(
135 r#"
136if redis.call('TYPE', KEYS[1])['ok'] ~= 'hash' then
137 return 0
138end
139redis.call('EXPIRE', KEYS[1], ARGV[1])
140if ARGV[3] == '1' then
141 redis.call('EXPIRE', KEYS[2], ARGV[2])
142end
106143return 1
107144"#,
108145 )
109146});
110147
148static DELETE_SCRIPT: LazyLock<Script> = LazyLock::new(|| {
149 Script::new(
150 r#"
151local deleted = redis.call('DEL', KEYS[1])
152if ARGV[2] == '1' then
153 redis.call('SREM', KEYS[2], ARGV[1])
154end
155return deleted
156"#,
157 )
158});
159
160static REVOKE_USER_SCRIPT: LazyLock<Script> = LazyLock::new(|| {
161 Script::new(
162 r#"
163local members = redis.call('SMEMBERS', KEYS[1])
164for _, member in ipairs(members) do
165 redis.call('DEL', ARGV[1] .. member)
166end
167redis.call('DEL', KEYS[1])
168return #members
169"#,
170 )
171});
172
111173#[derive(Clone)]
112174pub struct RedisStore {
113175 cache: Cache,
@@ -130,6 +192,14 @@
130192 self.cache.key(&[KEY_PREFIX, session_key.as_str()])
131193 }
132194
195 fn bucket_key(&self, user_id: Option<i64>) -> String {
196 self.cache.key(&[USER_BUCKET_PREFIX, &bucket_user(user_id)])
197 }
198
199 fn session_key_prefix(&self) -> String {
200 self.cache.key(&[KEY_PREFIX, ""])
201 }
202
133203 async fn connection(&self) -> Result<CacheConnection, SessionError> {
134204 Ok(self.cache.acquire().await?)
135205 }
@@ -152,12 +222,25 @@
152222}
153223
154224impl SessionStore for RedisStore {
155 async fn load(&self, session_key: &SessionKey) -> Result<Option<SessionState>, SessionError> {
225 async fn load(
226 &self,
227 session_key: &SessionKey,
228 ) -> Result<Option<(SessionState, Duration)>, SessionError> {
156229 let mut connection = self.connection().await?;
157230 let mut invocation = LOAD_SCRIPT.prepare_invoke();
158231 invocation.key(self.storage_key(session_key));
159232 let entries: Vec<String> = invocation.invoke_async(&mut connection).await?;
160 Ok(state_from_entries(entries))
233 let Some((ttl, entries)) = entries.split_first() else {
234 return Ok(None);
235 };
236 let ttl = ttl.parse::<i64>().unwrap_or(0);
237 if ttl <= 0 {
238 return Ok(None);
239 }
240 let Some(state) = state_from_entries(entries.to_vec()) else {
241 return Ok(None);
242 };
243 Ok(Some((state, Duration::seconds(ttl))))
161244 }
162245
163246 async fn save(
@@ -170,11 +253,18 @@
170253 "the session state to save cannot be empty",
171254 ));
172255 }
256 let user_id = user_id_of(&session_state);
257 let bucket_ttl = ttl_seconds(ttl);
173258 for _ in 0..SAVE_ATTEMPTS {
174259 let session_key = generate_session_key();
175260 let mut invocation = SAVE_SCRIPT.prepare_invoke();
176 invocation.key(self.storage_key(&session_key));
261 invocation
262 .key(self.storage_key(&session_key))
263 .key(self.bucket_key(user_id));
177264 invocation.arg(ttl_seconds(ttl));
265 invocation.arg(bucket_ttl);
266 invocation.arg(session_key.as_str());
267 invocation.arg(if user_id.is_some() { "1" } else { "0" });
178268 for (field, value) in &session_state {
179269 invocation.arg(field).arg(value);
180270 }
@@ -200,10 +290,20 @@
200290 session_key: SessionKey,
201291 diff: SessionDiff,
202292 ttl: &Duration,
293 previous_user_id: Option<i64>,
294 user_id: Option<i64>,
203295 ) -> Result<SessionKey, SessionError> {
204296 let mut invocation = UPDATE_SCRIPT.prepare_invoke();
205 invocation.key(self.storage_key(&session_key));
206 append_diff(&mut invocation, &diff, ttl);
297 invocation
298 .key(self.storage_key(&session_key))
299 .key(self.bucket_key(previous_user_id))
300 .key(self.bucket_key(user_id));
301 invocation.arg(ttl_seconds(ttl));
302 invocation.arg(ttl_seconds(ttl));
303 invocation.arg(session_key.as_str());
304 invocation.arg(if previous_user_id.is_some() { "1" } else { "0" });
305 invocation.arg(if user_id.is_some() { "1" } else { "0" });
306 append_diff_body(&mut invocation, &diff);
207307 let mut connection = self.connection().await?;
208308 let applied: i64 = invocation.invoke_async(&mut connection).await?;
209309 if applied != 1 {
@@ -217,14 +317,24 @@
217317 session_key: SessionKey,
218318 diff: SessionDiff,
219319 ttl: &Duration,
320 previous_user_id: Option<i64>,
321 user_id: Option<i64>,
220322 ) -> Result<Option<SessionKey>, SessionError> {
221323 for _ in 0..SAVE_ATTEMPTS {
222324 let new_session_key = self.rotated_key(&session_key)?;
223325 let mut invocation = ROTATE_SCRIPT.prepare_invoke();
224326 invocation
225327 .key(self.storage_key(&session_key))
226 .key(self.storage_key(&new_session_key));
227 append_diff(&mut invocation, &diff, ttl);
328 .key(self.storage_key(&new_session_key))
329 .key(self.bucket_key(previous_user_id))
330 .key(self.bucket_key(user_id));
331 invocation.arg(ttl_seconds(ttl));
332 invocation.arg(ttl_seconds(ttl));
333 invocation.arg(session_key.as_str());
334 invocation.arg(new_session_key.as_str());
335 invocation.arg(if previous_user_id.is_some() { "1" } else { "0" });
336 invocation.arg(if user_id.is_some() { "1" } else { "0" });
337 append_diff_body(&mut invocation, &diff);
228338 let mut connection = self.connection().await?;
229339 let outcome: i64 = invocation.invoke_async(&mut connection).await?;
230340 match outcome {
@@ -248,24 +358,59 @@
248358 &self,
249359 session_key: &SessionKey,
250360 ttl: &Duration,
361 user_id: Option<i64>,
251362 ) -> Result<(), SessionError> {
363 let mut invocation = UPDATE_TTL_SCRIPT.prepare_invoke();
364 invocation
365 .key(self.storage_key(session_key))
366 .key(self.bucket_key(user_id));
367 invocation.arg(ttl_seconds(ttl));
368 invocation.arg(ttl_seconds(ttl));
369 invocation.arg(if user_id.is_some() { "1" } else { "0" });
252370 let mut connection = self.connection().await?;
253 let renewed: bool = connection
254 .expire(self.storage_key(session_key), ttl_seconds(ttl))
255 .await?;
256 if !renewed {
371 let renewed: i64 = invocation.invoke_async(&mut connection).await?;
372 if renewed != 1 {
257373 return Err(SessionError::Purged);
258374 }
259375 Ok(())
260376 }
261377
262 async fn delete(&self, session_key: &SessionKey) -> Result<(), SessionError> {
378 async fn delete(
379 &self,
380 session_key: &SessionKey,
381 user_id: Option<i64>,
382 ) -> Result<(), SessionError> {
383 let mut invocation = DELETE_SCRIPT.prepare_invoke();
384 invocation
385 .key(self.storage_key(session_key))
386 .key(self.bucket_key(user_id));
387 invocation.arg(session_key.as_str());
388 invocation.arg(if user_id.is_some() { "1" } else { "0" });
263389 let mut connection = self.connection().await?;
264 let _: usize = connection.del(self.storage_key(session_key)).await?;
390 let _: i64 = invocation.invoke_async(&mut connection).await?;
265391 Ok(())
266392 }
393
394 async fn revoke_user(&self, user_id: i64) -> Result<usize, SessionError> {
395 let mut invocation = REVOKE_USER_SCRIPT.prepare_invoke();
396 invocation.key(self.bucket_key(Some(user_id)));
397 invocation.arg(self.session_key_prefix());
398 let mut connection = self.connection().await?;
399 let revoked: usize = invocation.invoke_async(&mut connection).await?;
400 Ok(revoked)
401 }
267402}
268403
404fn bucket_user(user_id: Option<i64>) -> String {
405 user_id.map(|id| id.to_string()).unwrap_or_default()
406}
407
408fn user_id_of(state: &SessionState) -> Option<i64> {
409 state
410 .get(crate::state::SESSION_USER_ID)
411 .and_then(|value| value.parse::<i64>().ok())
412}
413
269414fn state_from_entries(entries: Vec<String>) -> Option<SessionState> {
270415 if entries.is_empty() {
271416 return None;
@@ -278,8 +423,7 @@
278423 Some(state)
279424}
280425
281fn append_diff(invocation: &mut ScriptInvocation<'_>, diff: &SessionDiff, ttl: &Duration) {
282 invocation.arg(ttl_seconds(ttl));
426fn append_diff_body(invocation: &mut ScriptInvocation<'_>, diff: &SessionDiff) {
283427 invocation.arg(diff.set.len() as i64);
284428 for (field, value) in &diff.set {
285429 invocation.arg(field).arg(value);
Modified lib/session/src/state.rs lib/session/src/state.rs +29 −0 View lib/session/src/state.rs
@@ -13,6 +13,8 @@
1313pub const SESSION_CLIENT_IP: &str = "client_ip";
1414pub const SESSION_USER_AGENT: &str = "user_agent";
1515pub const SESSION_SECURITY_VERSION: &str = "security_version";
16pub const SESSION_AUTH_SESSION_ID: &str = "auth_session_id";
17pub const SESSION_MFA_VERIFIED: &str = "mfa_verified";
1618
1719#[derive(Clone, Default)]
1820pub struct Session {
@@ -160,10 +162,37 @@
160162 self.get(SESSION_USER_ID)
161163 }
162164
165 pub fn uid(&self) -> Option<i64> {
166 self.user_id().ok().flatten()
167 }
168
169 pub fn is_authenticated(&self) -> bool {
170 self.uid().is_some()
171 }
172
173 pub fn session_id(&self) -> Option<String> {
174 self.get(SESSION_AUTH_SESSION_ID).ok().flatten()
175 }
176
177 pub fn mfa_verified(&self) -> bool {
178 self.get(SESSION_MFA_VERIFIED)
179 .ok()
180 .flatten()
181 .unwrap_or(false)
182 }
183
163184 pub fn set_user_id(&self, user_id: i64) -> Result<(), SessionError> {
164185 self.set(SESSION_USER_ID, user_id)
165186 }
166187
188 pub fn set_auth_session_id(&self, session_id: impl Into<String>) -> Result<(), SessionError> {
189 self.set(SESSION_AUTH_SESSION_ID, session_id.into())
190 }
191
192 pub fn set_mfa_verified(&self, verified: bool) -> Result<(), SessionError> {
193 self.set(SESSION_MFA_VERIFIED, verified)
194 }
195
167196 pub fn clear_user_id(&self) {
168197 self.remove(SESSION_USER_ID);
169198 }
Modified lib/session/src/store.rs lib/session/src/store.rs +13 −2 View lib/session/src/store.rs
@@ -24,7 +24,7 @@
2424 fn load(
2525 &self,
2626 session_key: &SessionKey,
27 ) -> impl Future<Output = Result<Option<SessionState>, SessionError>>;
27 ) -> impl Future<Output = Result<Option<(SessionState, Duration)>, SessionError>>;
2828
2929 fn save(
3030 &self,
@@ -37,6 +37,8 @@
3737 session_key: SessionKey,
3838 diff: SessionDiff,
3939 ttl: &Duration,
40 previous_user_id: Option<i64>,
41 user_id: Option<i64>,
4042 ) -> impl Future<Output = Result<SessionKey, SessionError>>;
4143
4244 fn rotate(
@@ -44,15 +46,24 @@
4446 session_key: SessionKey,
4547 diff: SessionDiff,
4648 ttl: &Duration,
49 previous_user_id: Option<i64>,
50 user_id: Option<i64>,
4751 ) -> impl Future<Output = Result<Option<SessionKey>, SessionError>>;
4852
4953 fn update_ttl(
5054 &self,
5155 session_key: &SessionKey,
5256 ttl: &Duration,
57 user_id: Option<i64>,
5358 ) -> impl Future<Output = Result<(), SessionError>>;
5459
55 fn delete(&self, session_key: &SessionKey) -> impl Future<Output = Result<(), SessionError>>;
60 fn delete(
61 &self,
62 session_key: &SessionKey,
63 user_id: Option<i64>,
64 ) -> impl Future<Output = Result<(), SessionError>>;
65
66 fn revoke_user(&self, user_id: i64) -> impl Future<Output = Result<usize, SessionError>>;
5667}
5768
5869pub fn generate_session_key() -> SessionKey {
Modified lib/space/src/handlers/accept_invite.rs lib/space/src/handlers/accept_invite.rs +2 −2 View lib/space/src/handlers/accept_invite.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::invites::AcceptInviteCmd;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 post,
Modified lib/space/src/handlers/add_member.rs lib/space/src/handlers/add_member.rs +2 −2 View lib/space/src/handlers/add_member.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::members::{AddMemberCmd, MemberDto};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/assign_group.rs lib/space/src/handlers/assign_group.rs +2 −2 View lib/space/src/handlers/assign_group.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_member::MemberPath;
77use crate::services::groups::AssignGroupCmd;
88use crate::services::service::SpaceService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/ban_user.rs lib/space/src/handlers/ban_user.rs +2 −2 View lib/space/src/handlers/ban_user.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::bans::{BanDto, BanUserCmd};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/create_dir_node.rs lib/space/src/handlers/create_dir_node.rs +2 −2 View lib/space/src/handlers/create_dir_node.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dir::{CreateDirCmd, DirNodeDto};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/create_group.rs lib/space/src/handlers/create_group.rs +2 −2 View lib/space/src/handlers/create_group.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::groups::{CreateGroupCmd, GroupDto};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/create_invite.rs lib/space/src/handlers/create_invite.rs +2 −2 View lib/space/src/handlers/create_invite.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::invites::{CreateInviteCmd, InviteDto};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/create_join_rule.rs lib/space/src/handlers/create_join_rule.rs +2 −2 View lib/space/src/handlers/create_join_rule.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::join_rules::{CreateJoinRuleCmd, JoinRuleDto};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/create_room.rs lib/space/src/handlers/create_room.rs +2 −2 View lib/space/src/handlers/create_room.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::rooms::{CreateRoomCmd, RoomDto};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/create_space.rs lib/space/src/handlers/create_space.rs +2 −2 View lib/space/src/handlers/create_space.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::service::SpaceService;
77use crate::services::spaces::{CreateSpaceCmd, SpaceDto};
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 post,
Modified lib/space/src/handlers/delete_group.rs lib/space/src/handlers/delete_group.rs +2 −2 View lib/space/src/handlers/delete_group.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_group::GroupPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/delete_join_rule.rs lib/space/src/handlers/delete_join_rule.rs +2 −2 View lib/space/src/handlers/delete_join_rule.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::join_rules::JoinRulePath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/delete_room.rs lib/space/src/handlers/delete_room.rs +2 −2 View lib/space/src/handlers/delete_room.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44use uuid::Uuid;
55
66use crate::errors::ApiError;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/delete_space.rs lib/space/src/handlers/delete_space.rs +2 −2 View lib/space/src/handlers/delete_space.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::service::SpaceService;
77use crate::services::spaces::SpaceNamePath;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/delete_space_image.rs lib/space/src/handlers/delete_space_image.rs +2 −2 View lib/space/src/handlers/delete_space_image.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::images::SpaceImageKindPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/explore_spaces.rs lib/space/src/handlers/explore_spaces.rs +2 −2 View lib/space/src/handlers/explore_spaces.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::join_requests::{
@@ -9,7 +9,7 @@
99};
1010use crate::services::service::SpaceService;
1111use crate::services::spaces::SpaceNamePath;
12use token::share::session;
12use ::session::share::session;
1313
1414#[utoipa::path(
1515 get,
Modified lib/space/src/handlers/get_ban.rs lib/space/src/handlers/get_ban.rs +2 −2 View lib/space/src/handlers/get_ban.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_member::MemberPath;
77use crate::services::bans::BanDto;
88use crate::services::service::SpaceService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/space/src/handlers/get_group.rs lib/space/src/handlers/get_group.rs +1 −1 View lib/space/src/handlers/get_group.rs
@@ -1,7 +1,7 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
34use serde::Deserialize;
4use token::Session;
55use utoipa::{IntoParams, ToSchema};
66use uuid::Uuid;
77
Modified lib/space/src/handlers/get_member.rs lib/space/src/handlers/get_member.rs +2 −2 View lib/space/src/handlers/get_member.rs
@@ -1,13 +1,13 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
34use serde::Deserialize;
4use token::Session;
55use utoipa::{IntoParams, ToSchema};
66
77use crate::errors::ApiError;
88use crate::services::members::MemberDto;
99use crate::services::service::SpaceService;
10use token::share::session;
10use ::session::share::session;
1111
1212#[derive(Debug, Clone, Deserialize, IntoParams, ToSchema)]
1313pub struct MemberPath {
Modified lib/space/src/handlers/get_space.rs lib/space/src/handlers/get_space.rs +1 −1 View lib/space/src/handlers/get_space.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::service::SpaceService;
Modified lib/space/src/handlers/get_space_dir_tree.rs lib/space/src/handlers/get_space_dir_tree.rs +2 −2 View lib/space/src/handlers/get_space_dir_tree.rs
@@ -1,13 +1,13 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
34use serde::Deserialize;
4use token::Session;
55
66use crate::errors::ApiError;
77use crate::services::dir::DirNodeDto;
88use crate::services::service::SpaceService;
99use crate::services::spaces::SpaceNamePath;
10use token::share::session;
10use ::session::share::session;
1111
1212#[derive(Debug, Clone, Deserialize, utoipa::IntoParams)]
1313pub struct DirTreeQuery {
Modified lib/space/src/handlers/get_space_image.rs lib/space/src/handlers/get_space_image.rs +1 −1 View lib/space/src/handlers/get_space_image.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::images::{SpaceImageDto, SpaceImageKindPath};
Modified lib/space/src/handlers/get_space_image_file.rs lib/space/src/handlers/get_space_image_file.rs +1 −1 View lib/space/src/handlers/get_space_image_file.rs
@@ -1,8 +1,8 @@
1use ::session::Session;
12use actix_web::http::header;
23use export::http::{Path, Query, Response, State};
34use imaging::layout::ImageVariant;
45use serde::Deserialize;
5use token::Session;
66use utoipa::{IntoParams, ToSchema};
77
88use crate::errors::ApiError;
Modified lib/space/src/handlers/join_group_self.rs lib/space/src/handlers/join_group_self.rs +2 −2 View lib/space/src/handlers/join_group_self.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_group::GroupPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 post,
Modified lib/space/src/handlers/join_requests.rs lib/space/src/handlers/join_requests.rs +2 −2 View lib/space/src/handlers/join_requests.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::join_requests::{CreateJoinRequestCmd, JoinRequestDto, JoinRequestPath};
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/leave_group_self.rs lib/space/src/handlers/leave_group_self.rs +2 −2 View lib/space/src/handlers/leave_group_self.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_group::GroupPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/list_bans.rs lib/space/src/handlers/list_bans.rs +2 −2 View lib/space/src/handlers/list_bans.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::bans::BanPage;
77use crate::services::service::SpaceService;
88use crate::services::spaces::{PageQuery, SpaceNamePath};
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/space/src/handlers/list_dir_group_overwrites.rs lib/space/src/handlers/list_dir_group_overwrites.rs +2 −2 View lib/space/src/handlers/list_dir_group_overwrites.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dir::{DirPath, GroupOverwriteDto};
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/space/src/handlers/list_dir_user_overwrites.rs lib/space/src/handlers/list_dir_user_overwrites.rs +2 −2 View lib/space/src/handlers/list_dir_user_overwrites.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dir::{DirPath, UserOverwriteDto};
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/space/src/handlers/list_groups.rs lib/space/src/handlers/list_groups.rs +2 −2 View lib/space/src/handlers/list_groups.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::groups::GroupPage;
77use crate::services::service::SpaceService;
88use crate::services::spaces::{PageQuery, SpaceNamePath};
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/space/src/handlers/list_invites.rs lib/space/src/handlers/list_invites.rs +2 −2 View lib/space/src/handlers/list_invites.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::invites::InvitePage;
77use crate::services::service::SpaceService;
88use crate::services::spaces::{PageQuery, SpaceNamePath};
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/space/src/handlers/list_join_rules.rs lib/space/src/handlers/list_join_rules.rs +2 −2 View lib/space/src/handlers/list_join_rules.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::join_rules::JoinRuleDto;
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/space/src/handlers/list_members.rs lib/space/src/handlers/list_members.rs +2 −2 View lib/space/src/handlers/list_members.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::members::MemberPage;
77use crate::services::service::SpaceService;
88use crate::services::spaces::{PageQuery, SpaceNamePath};
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/space/src/handlers/list_spaces.rs lib/space/src/handlers/list_spaces.rs +2 −2 View lib/space/src/handlers/list_spaces.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::service::SpaceService;
77use crate::services::spaces::{PageQuery, SpacePage};
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/space/src/handlers/move_dir_node.rs lib/space/src/handlers/move_dir_node.rs +2 −2 View lib/space/src/handlers/move_dir_node.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dir::{DirNodeDto, DirPath, MoveDirCmd};
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 patch,
Modified lib/space/src/handlers/reject_invite.rs lib/space/src/handlers/reject_invite.rs +2 −2 View lib/space/src/handlers/reject_invite.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::invites::AcceptInviteCmd;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 post,
Modified lib/space/src/handlers/remove_dir_group_overwrite.rs lib/space/src/handlers/remove_dir_group_overwrite.rs +2 −2 View lib/space/src/handlers/remove_dir_group_overwrite.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::set_dir_group_overwrite::DirGroupPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/remove_dir_user_overwrite.rs lib/space/src/handlers/remove_dir_user_overwrite.rs +2 −2 View lib/space/src/handlers/remove_dir_user_overwrite.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::set_dir_user_overwrite::DirUserPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/remove_member.rs lib/space/src/handlers/remove_member.rs +2 −2 View lib/space/src/handlers/remove_member.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_member::MemberPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/repair_dir_parents.rs lib/space/src/handlers/repair_dir_parents.rs +2 −2 View lib/space/src/handlers/repair_dir_parents.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dir::RepairDirResp;
77use crate::services::service::SpaceService;
88use crate::services::spaces::SpaceNamePath;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 post,
Modified lib/space/src/handlers/revoke_invite.rs lib/space/src/handlers/revoke_invite.rs +2 −2 View lib/space/src/handlers/revoke_invite.rs
@@ -1,14 +1,14 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
34use serde::Deserialize;
4use token::Session;
55use utoipa::{IntoParams, ToSchema};
66use uuid::Uuid;
77
88use crate::errors::ApiError;
99use crate::services::invites::InviteDto;
1010use crate::services::service::SpaceService;
11use token::share::session;
11use ::session::share::session;
1212
1313#[derive(Debug, Clone, Deserialize, IntoParams, ToSchema)]
1414pub struct InvitePath {
Modified lib/space/src/handlers/self_member.rs lib/space/src/handlers/self_member.rs +2 −2 View lib/space/src/handlers/self_member.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::members::{MemberDto, UpdateMemberCmd};
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 patch,
Modified lib/space/src/handlers/set_dir_group_overwrite.rs lib/space/src/handlers/set_dir_group_overwrite.rs +2 −2 View lib/space/src/handlers/set_dir_group_overwrite.rs
@@ -1,14 +1,14 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
34use serde::Deserialize;
4use token::Session;
55use utoipa::{IntoParams, ToSchema};
66use uuid::Uuid;
77
88use crate::errors::ApiError;
99use crate::services::dir::{GroupOverwriteDto, SetOverwriteCmd};
1010use crate::services::service::SpaceService;
11use token::share::session;
11use ::session::share::session;
1212
1313#[derive(Debug, Clone, Deserialize, IntoParams, ToSchema)]
1414pub struct DirGroupPath {
Modified lib/space/src/handlers/set_dir_user_overwrite.rs lib/space/src/handlers/set_dir_user_overwrite.rs +2 −2 View lib/space/src/handlers/set_dir_user_overwrite.rs
@@ -1,14 +1,14 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
34use serde::Deserialize;
4use token::Session;
55use utoipa::{IntoParams, ToSchema};
66use uuid::Uuid;
77
88use crate::errors::ApiError;
99use crate::services::dir::{SetOverwriteCmd, UserOverwriteDto};
1010use crate::services::service::SpaceService;
11use token::share::session;
11use ::session::share::session;
1212
1313#[derive(Debug, Clone, Deserialize, IntoParams, ToSchema)]
1414pub struct DirUserPath {
Modified lib/space/src/handlers/unassign_group.rs lib/space/src/handlers/unassign_group.rs +2 −2 View lib/space/src/handlers/unassign_group.rs
@@ -1,13 +1,13 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
34use serde::Deserialize;
4use token::Session;
55use utoipa::{IntoParams, ToSchema};
66use uuid::Uuid;
77
88use crate::errors::ApiError;
99use crate::services::service::SpaceService;
10use token::share::session;
10use ::session::share::session;
1111
1212#[derive(Debug, Clone, Deserialize, IntoParams, ToSchema)]
1313pub struct MemberGroupPath {
Modified lib/space/src/handlers/unban_user.rs lib/space/src/handlers/unban_user.rs +2 −2 View lib/space/src/handlers/unban_user.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_member::MemberPath;
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/space/src/handlers/update_ban.rs lib/space/src/handlers/update_ban.rs +2 −2 View lib/space/src/handlers/update_ban.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_member::MemberPath;
77use crate::services::bans::{BanDto, UpdateBanCmd};
88use crate::services::service::SpaceService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 patch,
Modified lib/space/src/handlers/update_dir_node.rs lib/space/src/handlers/update_dir_node.rs +2 −2 View lib/space/src/handlers/update_dir_node.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::dir::{DirNodeDto, DirPath, UpdateDirCmd};
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 patch,
Modified lib/space/src/handlers/update_group.rs lib/space/src/handlers/update_group.rs +2 −2 View lib/space/src/handlers/update_group.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_group::GroupPath;
77use crate::services::groups::{GroupDto, UpdateGroupCmd};
88use crate::services::service::SpaceService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 patch,
Modified lib/space/src/handlers/update_join_rule.rs lib/space/src/handlers/update_join_rule.rs +2 −2 View lib/space/src/handlers/update_join_rule.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::join_rules::{JoinRuleDto, JoinRulePath, UpdateJoinRuleCmd};
77use crate::services::service::SpaceService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 patch,
Modified lib/space/src/handlers/update_member.rs lib/space/src/handlers/update_member.rs +2 −2 View lib/space/src/handlers/update_member.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::handlers::get_member::MemberPath;
77use crate::services::members::{MemberDto, UpdateMemberCmd};
88use crate::services::service::SpaceService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 patch,
Modified lib/space/src/handlers/update_space.rs lib/space/src/handlers/update_space.rs +2 −2 View lib/space/src/handlers/update_space.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::service::SpaceService;
77use crate::services::spaces::{SpaceDto, SpaceNamePath, UpdateSpaceCmd};
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 patch,
Modified lib/space/src/handlers/upload_space_image.rs lib/space/src/handlers/upload_space_image.rs +2 −2 View lib/space/src/handlers/upload_space_image.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use actix_web::http::header::CONTENT_TYPE;
23use export::http::{Bytes, HeaderMap, Path, Query, State};
34use export::rest::{AppResponseData, NoData};
4use token::Session;
55
66use crate::errors::ApiError;
77use crate::services::images::{SpaceImageDto, SpaceImageKindPath, SpaceImageUploadQuery};
88use crate::services::service::SpaceService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 put,
Modified lib/space/src/services/service.rs lib/space/src/services/service.rs +2 −2 View lib/space/src/services/service.rs
@@ -43,12 +43,12 @@
4343 text: &str,
4444 html: &str,
4545 ) -> Result<(), SpaceError> {
46 let Some(client) = self.state.email_rpc.as_ref() else {
46 let Some(client) = self.state.mail.as_ref() else {
4747 tracing::warn!(to, "email rpc disabled; skipping space mail");
4848 return Ok(());
4949 };
5050 client
51 .send_mail(to, subject, text, html)
51 .send_mail(to, subject, text, html, None)
5252 .await
5353 .map_err(|error| SpaceError::Internal(format!("email send failed: {error}")))
5454 }
Modified lib/space/src/share/guard.rs lib/space/src/share/guard.rs +1 −1 View lib/space/src/share/guard.rs
@@ -1 +1 @@
1pub use token::share::guard::session_guard as space_guard;
1pub use ::session::share::guard::session_guard as space_guard;
Modified lib/space/Cargo.toml lib/space/Cargo.toml +1 −1 View lib/space/Cargo.toml
@@ -11,7 +11,7 @@
1111i18n = { workspace = true }
1212imaging = { workspace = true }
1313models = { workspace = true }
14token = { workspace = true }
14session = { workspace = true }
1515auth = { workspace = true }
1616prost-types = { workspace = true }
1717storage = { workspace = true }
Modified lib/user/src/handlers/create_meme.rs lib/user/src/handlers/create_meme.rs +2 −2 View lib/user/src/handlers/create_meme.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::profile::{MemeDto, UpsertMemeCmd};
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 post,
Modified lib/user/src/handlers/delete_avatar.rs lib/user/src/handlers/delete_avatar.rs +2 −2 View lib/user/src/handlers/delete_avatar.rs
@@ -1,10 +1,10 @@
1use ::session::Session;
12use export::http::State;
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::service::UserService;
7use token::share::session;
7use ::session::share::session;
88
99#[utoipa::path(
1010 delete,
Modified lib/user/src/handlers/delete_meme.rs lib/user/src/handlers/delete_meme.rs +2 −2 View lib/user/src/handlers/delete_meme.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44use uuid::Uuid;
55
66use crate::errors::ApiError;
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/user/src/handlers/delete_push_subscription.rs lib/user/src/handlers/delete_push_subscription.rs +2 −2 View lib/user/src/handlers/delete_push_subscription.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44use uuid::Uuid;
55
66use crate::errors::ApiError;
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/user/src/handlers/get_avatar.rs lib/user/src/handlers/get_avatar.rs +2 −2 View lib/user/src/handlers/get_avatar.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::State;
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::avatar::AvatarDto;
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/user/src/handlers/get_profile_detail.rs lib/user/src/handlers/get_profile_detail.rs +1 −1 View lib/user/src/handlers/get_profile_detail.rs
@@ -1,6 +1,6 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::profile::ProfileDetailDto;
Modified lib/user/src/handlers/get_user_avatar.rs lib/user/src/handlers/get_user_avatar.rs +2 −2 View lib/user/src/handlers/get_user_avatar.rs
@@ -1,8 +1,8 @@
1use ::session::Session;
2use ::session::share::session;
13use actix_web::http::header;
24use export::http::{Path, Query, Response, State};
35use imaging::layout::ImageVariant;
4use token::Session;
5use token::share::session;
66use serde::Deserialize;
77use utoipa::{IntoParams, ToSchema};
88
Modified lib/user/src/handlers/list_memes.rs lib/user/src/handlers/list_memes.rs +2 −2 View lib/user/src/handlers/list_memes.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::profile::{ListLimitQuery, MemeDto};
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/user/src/handlers/list_push_subscriptions.rs lib/user/src/handlers/list_push_subscriptions.rs +2 −2 View lib/user/src/handlers/list_push_subscriptions.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::push_subscriptions::PushSubscriptionDto;
77use crate::services::service::UserService;
88use crate::share::page::PageQuery;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/user/src/handlers/list_saved_messages.rs lib/user/src/handlers/list_saved_messages.rs +2 −2 View lib/user/src/handlers/list_saved_messages.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::notifications::SavedMessageDto;
77use crate::services::service::UserService;
88use crate::share::page::PageQuery;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/user/src/handlers/my_reports.rs lib/user/src/handlers/my_reports.rs +2 −2 View lib/user/src/handlers/my_reports.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::notifications::UserReportDto;
77use crate::services::service::UserService;
88use crate::share::page::PageQuery;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/user/src/handlers/my_spaces.rs lib/user/src/handlers/my_spaces.rs +2 −2 View lib/user/src/handlers/my_spaces.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::profile::MySpaceDto;
77use crate::services::service::UserService;
88use crate::share::page::PageQuery;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/user/src/handlers/my_suspensions.rs lib/user/src/handlers/my_suspensions.rs +2 −2 View lib/user/src/handlers/my_suspensions.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::service::UserService;
77use crate::services::suspensions::{IncludeRevokedQuery, SuspensionDto};
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 get,
Modified lib/user/src/handlers/recent_mentions.rs lib/user/src/handlers/recent_mentions.rs +2 −2 View lib/user/src/handlers/recent_mentions.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Query, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::notifications::RecentMentionDto;
77use crate::services::profile::ListLimitQuery;
88use crate::services::service::UserService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 get,
Modified lib/user/src/handlers/save_message.rs lib/user/src/handlers/save_message.rs +2 −2 View lib/user/src/handlers/save_message.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::notifications::{SaveMessageCmd, SavedMessageDto};
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 post,
Modified lib/user/src/handlers/unsave_message.rs lib/user/src/handlers/unsave_message.rs +2 −2 View lib/user/src/handlers/unsave_message.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44use uuid::Uuid;
55
66use crate::errors::ApiError;
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 delete,
Modified lib/user/src/handlers/update_meme.rs lib/user/src/handlers/update_meme.rs +2 −2 View lib/user/src/handlers/update_meme.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use export::http::{Json, Path, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44use uuid::Uuid;
55
66use crate::errors::ApiError;
77use crate::services::profile::{MemeDto, UpsertMemeCmd};
88use crate::services::service::UserService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 put,
Modified lib/user/src/handlers/upload_avatar.rs lib/user/src/handlers/upload_avatar.rs +2 −2 View lib/user/src/handlers/upload_avatar.rs
@@ -1,12 +1,12 @@
1use ::session::Session;
12use actix_web::http::header::CONTENT_TYPE;
23use export::http::{Bytes, HeaderMap, State};
34use export::rest::{AppResponseData, NoData};
4use token::Session;
55
66use crate::errors::ApiError;
77use crate::services::avatar::AvatarDto;
88use crate::services::service::UserService;
9use token::share::session;
9use ::session::share::session;
1010
1111#[utoipa::path(
1212 put,
Modified lib/user/src/handlers/upsert_push_subscription.rs lib/user/src/handlers/upsert_push_subscription.rs +2 −2 View lib/user/src/handlers/upsert_push_subscription.rs
@@ -1,11 +1,11 @@
1use ::session::Session;
12use export::http::{Json, State};
23use export::rest::{AppResponseData, NoData};
3use token::Session;
44
55use crate::errors::ApiError;
66use crate::services::push_subscriptions::{PushSubscriptionDto, UpsertPushCmd};
77use crate::services::service::UserService;
8use token::share::session;
8use ::session::share::session;
99
1010#[utoipa::path(
1111 post,
Modified lib/user/src/share/guard.rs lib/user/src/share/guard.rs +1 −1 View lib/user/src/share/guard.rs
@@ -1 +1 @@
1pub use token::share::guard::session_guard as user_guard;
1pub use ::session::share::guard::session_guard as user_guard;
Modified lib/user/Cargo.toml lib/user/Cargo.toml +1 −1 View lib/user/Cargo.toml
@@ -10,7 +10,7 @@
1010models = { workspace = true }
1111i18n = { workspace = true }
1212imaging = { workspace = true }
13token = { workspace = true }
13session = { workspace = true }
1414storage = { workspace = true }
1515actix-web = { workspace = true }
1616sea-orm = { workspace = true }
Modified lib/webapi/src/auth/mod.rs lib/webapi/src/auth/mod.rs +1 −1 View lib/webapi/src/auth/mod.rs
@@ -1,8 +1,8 @@
11pub mod errors;
22pub mod handlers;
3pub mod session;
43pub mod openapi;
54pub mod routes;
65pub mod services;
6pub mod session;
77pub mod share;
88pub mod templates;
Modified lib/webapi/src/auth/openapi.rs lib/webapi/src/auth/openapi.rs +0 −3 View lib/webapi/src/auth/openapi.rs
@@ -35,7 +35,6 @@
3535 handlers::unread_notifications_count::unread_notifications_count,
3636 handlers::update_preferences::update_preferences,
3737 handlers::update_profile::update_profile,
38 handlers::jwt_request::jwt_request,
3938 handlers::password::change_password,
4039 handlers::two_factor::totp_status,
4140 handlers::two_factor::totp_setup,
@@ -69,8 +68,6 @@
6968 ReportDto,
7069 UnreadCountResp,
7170 NotificationType,
72 handlers::jwt_request::JwtRequestQuery,
73 handlers::jwt_request::JwtRequestResp,
7471 handlers::password::ChangePasswordCmd,
7572 handlers::two_factor::TotpStatusResp,
7673 handlers::two_factor::TotpSetupResp,
Modified lib/webapi/src/auth/routes.rs lib/webapi/src/auth/routes.rs +1 −7 View lib/webapi/src/auth/routes.rs
@@ -17,15 +17,13 @@
1717use crate::auth::handlers::update_preferences::update_preferences;
1818use crate::auth::handlers::update_profile::update_profile;
1919use crate::auth::handlers::users;
20use crate::auth::services::AuthService;
2021use crate::auth::session;
21use crate::auth::services::AuthService;
2222
2323pub fn router(_service: AuthService) -> Router<AuthService> {
2424 let public = Router::<AuthService>::new()
2525 .route("/auth/login", get(session::login::login))
2626 .route("/auth/signup", get(session::login::signup))
27 .route("/auth/callback", get(session::callback::callback))
28 .route("/auth/refresh", post(session::refresh::refresh))
2927 .route("/auth/logout", post(session::logout::logout))
3028 .route("/auth/agreements", get(list_agreements));
3129
@@ -42,10 +40,6 @@
4240 get(account_deletion_status)
4341 .post(request_account_deletion)
4442 .delete(cancel_account_deletion),
45 )
46 .route(
47 "/auth/jwt-request",
48 get(crate::auth::handlers::jwt_request::jwt_request),
4943 )
5044 .route("/me/username", put(users::update_username))
5145 .route(
Modified lib/webapi/src/cleanup.rs lib/webapi/src/cleanup.rs +2 −2 View lib/webapi/src/cleanup.rs
@@ -9,11 +9,11 @@
99 */
1010use std::collections::HashMap;
1111
12use ::session::Session;
13use ::session::share::session;
1214use export::http::routing::{delete, get, post};
1315use export::http::{Json, Path, Router, State};
1416use export::rest::{AppResponseData, NoData};
15use token::Session;
16use token::share::session;
1717use models::dir::{dir_overwrite_group, dir_overwrite_users, dirs};
1818use models::issue::issues as boards;
1919use models::repo::repos;
Modified lib/webapi/src/lib.rs lib/webapi/src/lib.rs +9 −14 View lib/webapi/src/lib.rs
@@ -2,8 +2,6 @@
22pub mod cleanup;
33pub mod openapi;
44
5use std::sync::Arc;
6
75use actix_cors::Cors;
86
97use actix_web::http::Method;
@@ -46,7 +44,14 @@
4644
4745 let cleanup_router = cleanup::router(space.clone(), issues.clone(), git.clone());
4846
49 let public = Router::<()>::new()
47 let mut public = Router::<()>::new();
48 if state.kenauth.is_some() {
49 public = public.merge(
50 Router::<()>::new()
51 .setup(|scope| scope.configure(::auth::server::http::router::configure_api)),
52 );
53 }
54 let public = public
5055 .merge(crate::auth::routes::router(auth.clone()).with_state(auth.clone()))
5156 .merge(chat::routes::router(chat.clone(), space.clone()).with_state(chat.clone()))
5257 .merge(issues::routes::router(issues.clone()).with_state(issues))
@@ -67,15 +72,5 @@
6772 .nest("/pages", crate::auth::routes::pages_router(auth.clone()))
6873 .merge(export::health::router(state))
6974 .into_scope(web::scope(""))
70}
71
72pub fn verifier(state: &AppState) -> Option<Arc<token::JwtVerifier>> {
73 let client = state.kenauth.as_ref()?;
74 match token::JwtVerifier::with_identity(&state.config.jwt, client.service().signing().jwks()) {
75 Ok(verifier) => Some(verifier),
76 Err(error) => {
77 tracing::warn!(%error, "the JWT verifier could not be built");
78 None
79 }
80 }
75 .default_service(web::to(::auth::assets::serve))
8176}
Modified lib/webapi/src/openapi.rs lib/webapi/src/openapi.rs +3 −8 View lib/webapi/src/openapi.rs
@@ -23,14 +23,9 @@
2323- `POST /auth/logout` is idempotent: repeating it always succeeds with `200`.
2424
2525### Authentication
26- `session_cookie`: platform JWT carried in the `gitdata_session` cookie, minted
27 by the identity service from the same-domain session. `GET /auth/login`
28 redirects to the identity login page; `POST /auth/refresh` re-mints the JWT
29 from the session; `POST /auth/logout` revokes the identity session and clears
30 the cookie.
31- `basic_access_key`: HTTP Basic auth with an identity-issued access key.
32 **Scope: git repository endpoints only** (`/repos/*`, `/graphql`); it is NOT
33 accepted by chat/issues/space/user endpoints.
26- `session_cookie`: opaque session carried in the `session` cookie and stored in
27 Redis. `GET /auth/login` redirects to the same-origin login page;
28 `POST /auth/logout` revokes the session and clears the cookie.
3429
3530### URL & parameter style
3631- Paths are `kebab-case`, plural nouns, nesting expresses ownership.
Modified lib/webapi/Cargo.toml lib/webapi/Cargo.toml +1 −1 View lib/webapi/Cargo.toml
@@ -23,7 +23,7 @@
2323models = { workspace = true }
2424sea-orm = { workspace = true }
2525export = { workspace = true }
26token = { workspace = true }
26session = { workspace = true }
2727tokio = { workspace = true }
2828actix-web = { workspace = true }
2929actix-cors = { workspace = true }
Modified Cargo.lock Cargo.lock +12 −160 View Cargo.lock
@@ -773,7 +773,6 @@
773773 "config 1.0.0",
774774 "crypt",
775775 "db",
776 "ed25519-dalek",
777776 "email",
778777 "envelope",
779778 "events",
@@ -808,14 +807,11 @@
808807 "sha2 0.10.9",
809808 "sqlparser",
810809 "thiserror 2.0.21",
811 "token",
812810 "tokio",
813811 "tokio-stream",
814812 "tokio-util",
815813 "tonic",
816 "tonic-health",
817814 "tonic-prost",
818 "tonic-reflection",
819815 "tower",
820816 "tracing",
821817 "tracing-opentelemetry",
@@ -1274,12 +1270,12 @@
12741270 "sea-orm",
12751271 "serde",
12761272 "serde_json",
1273 "session",
12771274 "sha2 0.11.1",
12781275 "social",
12791276 "space",
12801277 "storage",
12811278 "time 0.3.55",
1282 "token",
12831279 "tokio",
12841280 "tokio-util",
12851281 "tracing",
@@ -1785,33 +1781,6 @@
17851781]
17861782
17871783[[package]]
1788name = "curve25519-dalek"
1789version = "4.1.3"
1790source = "registry+https://github.com/rust-lang/crates.io-index"
1791checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
1792dependencies = [
1793 "cfg-if",
1794 "cpufeatures 0.2.17",
1795 "curve25519-dalek-derive",
1796 "digest 0.10.7",
1797 "fiat-crypto",
1798 "rustc_version",
1799 "subtle",
1800 "zeroize",
1801]
1802
1803[[package]]
1804name = "curve25519-dalek-derive"
1805version = "0.1.1"
1806source = "registry+https://github.com/rust-lang/crates.io-index"
1807checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
1808dependencies = [
1809 "proc-macro2",
1810 "quote",
1811 "syn 2.0.119",
1812]
1813
1814[[package]]
18151784name = "darling"
18161785version = "0.20.11"
18171786source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2157,16 +2126,6 @@
21572126]
21582127
21592128[[package]]
2160name = "ed25519"
2161version = "2.2.3"
2162source = "registry+https://github.com/rust-lang/crates.io-index"
2163checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
2164dependencies = [
2165 "pkcs8 0.10.2",
2166 "signature 2.2.0",
2167]
2168
2169[[package]]
21702129name = "ed25519-compact"
21712130version = "2.4.2"
21722131source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2177,20 +2136,6 @@
21772136]
21782137
21792138[[package]]
2180name = "ed25519-dalek"
2181version = "2.2.0"
2182source = "registry+https://github.com/rust-lang/crates.io-index"
2183checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
2184dependencies = [
2185 "curve25519-dalek",
2186 "ed25519",
2187 "serde",
2188 "sha2 0.10.9",
2189 "subtle",
2190 "zeroize",
2191]
2192
2193[[package]]
21942139name = "either"
21952140version = "1.19.0"
21962141source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2224,18 +2169,11 @@
22242169name = "email"
22252170version = "1.0.0"
22262171dependencies = [
2227 "async-trait",
22282172 "base64 0.23.1",
22292173 "bytes",
2230 "chrono",
22312174 "config 1.0.0",
2232 "db",
2233 "envelope",
22342175 "events",
2235 "futures-util",
2236 "http 1.5.0",
22372176 "lettre",
2238 "maud",
22392177 "queue",
22402178 "serde",
22412179 "serde_json",
@@ -2402,11 +2340,11 @@
24022340 "sea-orm",
24032341 "serde",
24042342 "serde_json",
2343 "session",
24052344 "sha2 0.11.1",
24062345 "storage",
24072346 "thiserror 2.0.21",
24082347 "time 0.3.55",
2409 "token",
24102348 "tokio",
24112349 "tower",
24122350 "tracing",
@@ -2451,12 +2389,6 @@
24512389]
24522390
24532391[[package]]
2454name = "fiat-crypto"
2455version = "0.2.9"
2456source = "registry+https://github.com/rust-lang/crates.io-index"
2457checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
2458
2459[[package]]
24602392name = "figment"
24612393version = "0.10.19"
24622394source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2789,11 +2721,11 @@
27892721 "sea-orm",
27902722 "serde",
27912723 "serde_json",
2724 "session",
27922725 "sha2 0.11.1",
27932726 "space",
27942727 "thiserror 2.0.21",
27952728 "time 0.3.55",
2796 "token",
27972729 "tokio",
27982730 "tokio-util",
27992731 "tonic",
@@ -3639,9 +3571,9 @@
36393571 "sea-orm",
36403572 "serde",
36413573 "serde_json",
3574 "session",
36423575 "space",
36433576 "time 0.3.55",
3644 "token",
36453577 "tracing",
36463578 "utoipa 5.5.0",
36473579 "uuid",
@@ -3787,21 +3719,6 @@
37873719
37883720[[package]]
37893721name = "jsonwebtoken"
3790version = "9.3.1"
3791source = "registry+https://github.com/rust-lang/crates.io-index"
3792checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde"
3793dependencies = [
3794 "base64 0.22.1",
3795 "js-sys",
3796 "pem",
3797 "ring",
3798 "serde",
3799 "serde_json",
3800 "simple_asn1",
3801]
3802
3803[[package]]
3804name = "jsonwebtoken"
38053722version = "10.4.0"
38063723source = "registry+https://github.com/rust-lang/crates.io-index"
38073724checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc"
@@ -3883,9 +3800,11 @@
38833800 "queue",
38843801 "sea-orm",
38853802 "serde_json",
3886 "token",
3803 "session",
38873804 "tokio",
3805 "tokio-stream",
38883806 "tokio-util",
3807 "tonic",
38893808 "tracing",
38903809 "tracing-subscriber",
38913810 "utoipa 5.5.0",
@@ -4171,7 +4090,7 @@
41714090checksum = "bc9c914fdcfb38e7e48acfe5dfa1a64eb01a4e3f42c37f792e48b0705a8cc7c4"
41724091dependencies = [
41734092 "hmac 0.12.1",
4174 "jsonwebtoken 10.4.0",
4093 "jsonwebtoken",
41754094 "livekit-protocol",
41764095 "serde",
41774096 "sha2 0.10.9",
@@ -5759,9 +5678,9 @@
57595678 "sea-orm",
57605679 "serde",
57615680 "serde_json",
5681 "session",
57625682 "space",
57635683 "time 0.3.55",
5764 "token",
57655684 "tracing",
57665685 "utoipa 5.5.0",
57675686 "uuid",
@@ -7168,18 +7087,6 @@
71687087checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
71697088
71707089[[package]]
7171name = "simple_asn1"
7172version = "0.6.4"
7173source = "registry+https://github.com/rust-lang/crates.io-index"
7174checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d"
7175dependencies = [
7176 "num-bigint 0.4.8",
7177 "num-traits",
7178 "thiserror 2.0.21",
7179 "time 0.3.55",
7180]
7181
7182[[package]]
71837090name = "siphasher"
71847091version = "1.0.4"
71857092source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -7274,9 +7181,9 @@
72747181 "sea-orm",
72757182 "serde",
72767183 "serde_json",
7184 "session",
72777185 "storage",
72787186 "time 0.3.55",
7279 "token",
72807187 "tracing",
72817188 "utoipa 5.5.0",
72827189 "uuid",
@@ -7818,33 +7725,6 @@
78187725checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
78197726
78207727[[package]]
7821name = "token"
7822version = "1.0.0"
7823dependencies = [
7824 "actix-web",
7825 "async-trait",
7826 "base64 0.23.1",
7827 "bytes",
7828 "chrono",
7829 "config 1.0.0",
7830 "crypt",
7831 "ed25519-dalek",
7832 "envelope",
7833 "http 1.5.0",
7834 "jsonwebtoken 9.3.1",
7835 "prost-types 0.14.4",
7836 "proto",
7837 "reqwest 0.13.5",
7838 "serde",
7839 "serde_json",
7840 "sha2 0.10.9",
7841 "thiserror 2.0.21",
7842 "tokio",
7843 "tonic",
7844 "tracing",
7845]
7846
7847[[package]]
78487728name = "tokio"
78497729version = "1.54.1"
78507730source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -7901,7 +7781,6 @@
79017781 "futures-core",
79027782 "pin-project-lite",
79037783 "tokio",
7904 "tokio-util",
79057784]
79067785
79077786[[package]]
@@ -8074,19 +7953,6 @@
80747953]
80757954
80767955[[package]]
8077name = "tonic-health"
8078version = "0.14.6"
8079source = "registry+https://github.com/rust-lang/crates.io-index"
8080checksum = "fcfab99db777fba2802f0dfa861d1628d1ae916fb199d29819941f139ae85082"
8081dependencies = [
8082 "prost 0.14.4",
8083 "tokio",
8084 "tokio-stream",
8085 "tonic",
8086 "tonic-prost",
8087]
8088
8089[[package]]
80907956name = "tonic-prost"
80917957version = "0.14.9"
80927958source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -8114,20 +7980,6 @@
81147980]
81157981
81167982[[package]]
8117name = "tonic-reflection"
8118version = "0.14.6"
8119source = "registry+https://github.com/rust-lang/crates.io-index"
8120checksum = "acccd136a4bf19810a1fde9c74edc6129b42a66b44d0c1c8aaa67aeb49a146a7"
8121dependencies = [
8122 "prost 0.14.4",
8123 "prost-types 0.14.4",
8124 "tokio",
8125 "tokio-stream",
8126 "tonic",
8127 "tonic-prost",
8128]
8129
8130[[package]]
81317983name = "tower"
81327984version = "0.5.3"
81337985source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -8475,11 +8327,11 @@
84758327 "sea-orm",
84768328 "serde",
84778329 "serde_json",
8330 "session",
84788331 "sha2 0.11.1",
84798332 "space",
84808333 "storage",
84818334 "time 0.3.55",
8482 "token",
84838335 "tracing",
84848336 "utoipa 5.5.0",
84858337 "uuid",
@@ -8837,10 +8689,10 @@
88378689 "sea-orm",
88388690 "serde",
88398691 "serde_json",
8692 "session",
88408693 "sha2 0.11.1",
88418694 "space",
88428695 "time 0.3.55",
8843 "token",
88448696 "tokio",
88458697 "tracing",
88468698 "url 2.5.8",
Modified Cargo.toml Cargo.toml +0 −2 View Cargo.toml
@@ -36,7 +36,6 @@
3636oltp = { path = "lib/oltp" }
3737proto = { path = "lib/proto" }
3838session = { path = "lib/session" }
39token = { path = "lib/token" }
4039webapi = { path = "lib/webapi" }
4140pulls = { path = "lib/pulls" }
4241social = { path = "lib/social" }
@@ -89,7 +88,6 @@
8988livekit-protocol = "0.7.13"
9089anyhow = "1"
9190tracing-subscriber = { version = "0.3", features = ["env-filter"] }
92jsonwebtoken = "9"
9391
9492regex = "1"
9593url = "2"
Modified Dockerfile Dockerfile +1 −1 View Dockerfile
@@ -106,7 +106,7 @@
106106
107107USER gitdata
108108
109EXPOSE 7051 7021 7022
109EXPOSE 7051 7022
110110STOPSIGNAL SIGTERM
111111
112112HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
Modified vite.config.ts vite.config.ts +0 −1 View vite.config.ts
@@ -6,7 +6,6 @@
66export default defineConfig(({ mode }) => {
77 const env = loadEnv(mode, process.cwd(), '')
88 return {
9 // 前端源码在 view/ 下,产物输出到 view/dist(build.rs 会把它们编进二进制)。
109 root: 'view',
1110 publicDir: 'public',
1211 build: { outDir: 'dist', emptyOutDir: true },