scufflecloud_core/services/
sessions.rs1use 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}