scufflecloud_core/services/
sessions.rs

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