scufflecloud_core/services/
sessions.rs

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