scufflecloud_core/services/
sessions.rs

1use base64::Engine;
2use ext_traits::{OptionExt, RequestExt};
3use sha2::Digest;
4
5use crate::google_api;
6use crate::operations::Operation;
7use crate::operations::user_sessions::{InvalidateUserSessionRequest, RefreshUserSessionRequest};
8use crate::services::CoreSvc;
9
10#[async_trait::async_trait]
11impl<G: core_traits::Global> pb::scufflecloud::core::v1::sessions_service_server::SessionsService for CoreSvc<G> {
12    async fn login_with_magic_link(
13        &self,
14        req: tonic::Request<pb::scufflecloud::core::v1::LoginWithMagicLinkRequest>,
15    ) -> Result<tonic::Response<()>, tonic::Status> {
16        Operation::<G>::run(req).await.map(tonic::Response::new)
17    }
18
19    async fn complete_login_with_magic_link(
20        &self,
21        req: tonic::Request<pb::scufflecloud::core::v1::CompleteLoginWithMagicLinkRequest>,
22    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::NewUserSessionToken>, tonic::Status> {
23        Operation::<G>::run(req).await.map(tonic::Response::new)
24    }
25
26    async fn login_with_email_and_password(
27        &self,
28        req: tonic::Request<pb::scufflecloud::core::v1::LoginWithEmailAndPasswordRequest>,
29    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::NewUserSessionToken>, tonic::Status> {
30        Operation::<G>::run(req).await.map(tonic::Response::new)
31    }
32
33    async fn login_with_google(
34        &self,
35        req: tonic::Request<pb::scufflecloud::core::v1::LoginWithGoogleRequest>,
36    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::LoginWithGoogleResponse>, tonic::Status> {
37        let global = &req.global::<G>()?;
38        let payload = req.into_inner();
39
40        let device = payload.device.require("device")?;
41        let device_fingerprint = sha2::Sha256::digest(&device.public_key_data);
42        let state = base64::prelude::BASE64_URL_SAFE.encode(device_fingerprint);
43
44        let authorization_url = google_api::authorization_url(global, &state);
45
46        Ok(tonic::Response::new(pb::scufflecloud::core::v1::LoginWithGoogleResponse {
47            authorization_url,
48        }))
49    }
50
51    async fn complete_login_with_google(
52        &self,
53        req: tonic::Request<pb::scufflecloud::core::v1::CompleteLoginWithGoogleRequest>,
54    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::CompleteLoginWithGoogleResponse>, tonic::Status> {
55        Operation::<G>::run(req).await.map(tonic::Response::new)
56    }
57
58    async fn login_with_webauthn(
59        &self,
60        req: tonic::Request<pb::scufflecloud::core::v1::LoginWithWebauthnRequest>,
61    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::NewUserSessionToken>, tonic::Status> {
62        Operation::<G>::run(req).await.map(tonic::Response::new)
63    }
64
65    async fn create_user_session_request(
66        &self,
67        req: tonic::Request<pb::scufflecloud::core::v1::CreateUserSessionRequestRequest>,
68    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::UserSessionRequest>, tonic::Status> {
69        Operation::<G>::run(req).await.map(tonic::Response::new)
70    }
71
72    async fn get_user_session_request(
73        &self,
74        req: tonic::Request<pb::scufflecloud::core::v1::GetUserSessionRequestRequest>,
75    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::UserSessionRequest>, tonic::Status> {
76        Operation::<G>::run(req).await.map(tonic::Response::new)
77    }
78
79    async fn get_user_session_request_by_code(
80        &self,
81        req: tonic::Request<pb::scufflecloud::core::v1::GetUserSessionRequestByCodeRequest>,
82    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::UserSessionRequest>, tonic::Status> {
83        Operation::<G>::run(req).await.map(tonic::Response::new)
84    }
85
86    async fn approve_user_session_request_by_code(
87        &self,
88        req: tonic::Request<pb::scufflecloud::core::v1::ApproveUserSessionRequestByCodeRequest>,
89    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::UserSessionRequest>, tonic::Status> {
90        Operation::<G>::run(req).await.map(tonic::Response::new)
91    }
92
93    async fn complete_user_session_request(
94        &self,
95        req: tonic::Request<pb::scufflecloud::core::v1::CompleteUserSessionRequestRequest>,
96    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::NewUserSessionToken>, tonic::Status> {
97        Operation::<G>::run(req).await.map(tonic::Response::new)
98    }
99
100    async fn validate_mfa_for_user_session(
101        &self,
102        req: tonic::Request<pb::scufflecloud::core::v1::ValidateMfaForUserSessionRequest>,
103    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::UserSession>, tonic::Status> {
104        Operation::<G>::run(req).await.map(tonic::Response::new)
105    }
106
107    async fn refresh_user_session(
108        &self,
109        req: tonic::Request<()>,
110    ) -> Result<tonic::Response<pb::scufflecloud::core::v1::NewUserSessionToken>, tonic::Status> {
111        let (metadata, extensions, _) = req.into_parts();
112        let req = tonic::Request::from_parts(metadata, extensions, RefreshUserSessionRequest);
113        Operation::<G>::run(req).await.map(tonic::Response::new)
114    }
115
116    async fn invalidate_user_session(&self, req: tonic::Request<()>) -> Result<tonic::Response<()>, tonic::Status> {
117        let (metadata, extensions, _) = req.into_parts();
118        let req = tonic::Request::from_parts(metadata, extensions, InvalidateUserSessionRequest);
119        Operation::<G>::run(req).await.map(tonic::Response::new)
120    }
121}