1use crate::access_rules::AccessRules;
2use crate::auth::core::AuthInfo;
3use crate::errors::PAASServerError;
4use crate::session_storage::SessionStorage;
5use actix_web::web::Data;
6use actix_web::{web, HttpResponse};
7use libpep::data::traits::{HasStructure, Pseudonymizable, Rekeyable, Transcryptable};
8use libpep::factors::{EncryptionContext, RekeyInfoProvider};
9use libpep::transcryptor::{DistributedTranscryptor, Transcryptor};
10use log::{debug, error, info, warn};
11use paas_api::transcrypt::{
12 PseudonymizationBatchRequest, PseudonymizationBatchResponse, PseudonymizationRequest,
13 PseudonymizationResponse, RekeyBatchRequest, RekeyBatchResponse, RekeyRequest, RekeyResponse,
14 TranscryptionBatchRequest, TranscryptionBatchResponse, TranscryptionRequest,
15 TranscryptionResponse,
16};
17use serde::Serialize;
18
19pub async fn pseudonymize<T>(
20 item: web::Json<PseudonymizationRequest<T>>,
21 access_rules: Data<AccessRules>,
22 session_storage: Data<Box<dyn SessionStorage>>,
23 pep_system: Data<DistributedTranscryptor>,
24 user: web::ReqData<AuthInfo>,
25) -> Result<HttpResponse, PAASServerError>
26where
27 T: Pseudonymizable + Serialize,
28{
29 let session_storage = session_storage.get_ref();
30 let request = item.into_inner();
31
32 debug!(
33 "Processing pseudonymization request: domain={:?}→{:?} session={:?}→{:?} {}",
34 request.domain_from, request.domain_to, request.session_from, request.session_to, *user
35 );
36
37 if !access_rules.has_access(&user, &request.domain_from, &request.domain_to) {
38 warn!(
39 "Access denied: domain={:?}→{:?} {:?}",
40 request.domain_from, request.domain_to, *user
41 );
42 return Err(PAASServerError::AccessDenied {
43 from: format!("{:?}", request.domain_from.clone()),
44 to: format!("{:?}", request.domain_to.clone()),
45 });
46 }
47
48 let session_valid =
49 match session_storage.session_exists(user.sub.to_string(), request.session_to.clone()) {
50 Ok(valid) => valid,
51 Err(e) => {
52 error!(
53 "Failed to check if session exists: session={:?} {}",
54 request.session_to, *user
55 );
56 return Err(PAASServerError::SessionError(Box::new(e)));
57 }
58 };
59
60 if !session_valid {
61 warn!(
62 "Invalid session: session={:?} {}",
63 request.session_to, *user
64 );
65 return Err(PAASServerError::InvalidSession(
66 "Target session not owned by user".to_string(),
67 ));
68 }
69
70 let pseudonymization_info = pep_system.pseudonymization_info(
71 &request.domain_from,
72 &request.domain_to,
73 &request.session_from,
74 &request.session_to,
75 );
76
77 let result = pep_system.pseudonymize(&request.encrypted, &pseudonymization_info);
78
79 info!(
80 "Pseudonymized: domain={:?}→{:?} session={:?}→{:?} {}",
81 request.domain_from, request.domain_to, request.session_from, request.session_to, *user
82 );
83
84 Ok(HttpResponse::Ok().json(PseudonymizationResponse { result }))
85}
86
87pub async fn pseudonymize_batch<T>(
88 item: web::Json<PseudonymizationBatchRequest<T>>,
89 access_rules: Data<AccessRules>,
90 session_storage: Data<Box<dyn SessionStorage>>,
91 pep_system: Data<DistributedTranscryptor>,
92 user: web::ReqData<AuthInfo>,
93) -> Result<HttpResponse, PAASServerError>
94where
95 T: Pseudonymizable + Serialize + Clone + HasStructure,
96{
97 let session_storage = session_storage.get_ref();
98 let request = item.into_inner();
99 let batch_size = request.encrypted.len();
100
101 debug!(
102 "Processing batch pseudonymization request: domain={:?}→{:?} session={:?}→{:?} count={} {}",
103 request.domain_from,
104 request.domain_to,
105 request.session_from,
106 request.session_to,
107 batch_size,
108 *user
109 );
110
111 if !access_rules.has_access(&user, &request.domain_from, &request.domain_to) {
112 warn!(
113 "Access denied: domain={:?}→{:?} {}",
114 request.domain_from, request.domain_to, *user
115 );
116 return Err(PAASServerError::AccessDenied {
117 from: format!("{:?}", request.domain_from.clone()),
118 to: format!("{:?}", request.domain_to.clone()),
119 });
120 }
121
122 let session_valid =
123 match session_storage.session_exists(user.sub.to_string(), request.session_to.clone()) {
124 Ok(valid) => valid,
125 Err(e) => {
126 error!(
127 "Failed to check if session exists: session={:?} {}",
128 request.session_to, *user
129 );
130 return Err(PAASServerError::SessionError(Box::new(e)));
131 }
132 };
133
134 if !session_valid {
135 warn!(
136 "Invalid session: session={:?} {}",
137 request.session_to, *user
138 );
139 return Err(PAASServerError::InvalidSession(
140 "Target session not owned by user".to_string(),
141 ));
142 }
143
144 let mut encrypted_pseudonyms = request.encrypted.clone();
145 let mut rng = rand::rng();
146
147 let pseudonymization_info = pep_system.pseudonymization_info(
148 &request.domain_from,
149 &request.domain_to,
150 &request.session_from,
151 &request.session_to,
152 );
153
154 let msg_out = pep_system.pseudonymize_batch(
155 &mut encrypted_pseudonyms,
156 &pseudonymization_info,
157 &mut rng,
158 )?;
159
160 info!(
161 "Pseudonymized batch: domain={:?}→{:?} session={:?}→{:?} count={} {}",
162 request.domain_from,
163 request.domain_to,
164 request.session_from,
165 request.session_to,
166 batch_size,
167 *user
168 );
169
170 Ok(HttpResponse::Ok().json(PseudonymizationBatchResponse {
171 result: Vec::from(msg_out),
172 }))
173}
174
175#[allow(unreachable_code)]
176fn validate_rekey_request(
177 _session_to: &EncryptionContext,
178 _user: &AuthInfo,
179 _session_storage: &dyn SessionStorage,
180) -> Result<(), PAASServerError> {
181 return Err(PAASServerError::Unauthorized(
183 "Rekeying is currently disabled pending access rule implementation".to_string(),
184 ));
185
186 let session_valid =
187 match _session_storage.session_exists(_user.sub.to_string(), _session_to.clone()) {
188 Ok(valid) => valid,
189 Err(e) => {
190 error!(
191 "Failed to check if session exists: session={:?} {}",
192 _session_to, *_user
193 );
194 return Err(PAASServerError::SessionError(Box::new(e)));
195 }
196 };
197
198 if !session_valid {
199 warn!("Invalid session: session={:?} {}", _session_to, *_user);
200 return Err(PAASServerError::InvalidSession(
201 "Target session not owned by user".to_string(),
202 ));
203 }
204 Ok(())
205}
206
207pub async fn rekey<T>(
208 item: web::Json<RekeyRequest<T>>,
209 _access_rules: Data<AccessRules>,
210 session_storage: Data<Box<dyn SessionStorage>>,
211 pep_system: Data<DistributedTranscryptor>,
212 user: web::ReqData<AuthInfo>,
213) -> Result<HttpResponse, PAASServerError>
214where
215 T: Rekeyable + Serialize,
216 Transcryptor: RekeyInfoProvider<<T as Rekeyable>::RekeyInfo>,
217{
218 let session_storage = session_storage.get_ref();
219 let request = item.into_inner();
220
221 debug!(
222 "Processing rekey request: session={:?}→{:?} {}",
223 request.session_from, request.session_to, *user
224 );
225
226 validate_rekey_request(&request.session_to, &user, session_storage.as_ref())?;
227
228 let rekey_info = pep_system.rekey_info(&request.session_from, &request.session_to);
229
230 let result = pep_system.rekey(&request.encrypted, &rekey_info);
231
232 info!(
233 "Rekeyed: session={:?}→{:?} {}",
234 request.session_from, request.session_to, *user
235 );
236
237 Ok(HttpResponse::Ok().json(RekeyResponse { result }))
238}
239
240pub async fn rekey_batch<T>(
241 item: web::Json<RekeyBatchRequest<T>>,
242 _access_rules: Data<AccessRules>,
243 session_storage: Data<Box<dyn SessionStorage>>,
244 pep_system: Data<DistributedTranscryptor>,
245 user: web::ReqData<AuthInfo>,
246) -> Result<HttpResponse, PAASServerError>
247where
248 T: Rekeyable + Serialize + Clone + HasStructure,
249 Transcryptor: RekeyInfoProvider<<T as Rekeyable>::RekeyInfo>,
250 <T as Rekeyable>::RekeyInfo: Copy,
251{
252 let session_storage = session_storage.get_ref();
253 let request = item.into_inner();
254 let batch_size = request.encrypted.len();
255
256 debug!(
257 "Processing batch rekey request: session={:?}→{:?} count={} {}",
258 request.session_from, request.session_to, batch_size, *user
259 );
260 validate_rekey_request(&request.session_to, &user, session_storage.as_ref())?;
261
262 let rekey_info = pep_system.rekey_info(&request.session_from, &request.session_to);
263
264 let mut encrypted = request.encrypted.clone();
265 let mut rng = rand::rng();
266 let msg_out = pep_system.rekey_batch(&mut encrypted, &rekey_info, &mut rng)?;
267
268 info!(
269 "Rekeyed batch: session={:?}→{:?} count={} {}",
270 request.session_from, request.session_to, batch_size, *user
271 );
272
273 Ok(HttpResponse::Ok().json(RekeyBatchResponse {
274 result: Vec::from(msg_out),
275 }))
276}
277
278pub async fn transcrypt<T>(
279 item: web::Json<TranscryptionRequest<T>>,
280 access_rules: Data<AccessRules>,
281 session_storage: Data<Box<dyn SessionStorage>>,
282 pep_system: Data<DistributedTranscryptor>,
283 user: web::ReqData<AuthInfo>,
284) -> Result<HttpResponse, PAASServerError>
285where
286 T: Transcryptable + Serialize,
287{
288 let session_storage = session_storage.get_ref();
289 let request = item.into_inner();
290
291 debug!(
292 "Processing transcrypt request: domain={:?}→{:?} session={:?}→{:?} {}",
293 request.domain_from, request.domain_to, request.session_from, request.session_to, *user
294 );
295
296 if !access_rules.has_access(&user, &request.domain_from, &request.domain_to) {
297 warn!(
298 "Access denied: domain={:?}→{:?} {}",
299 request.domain_from, request.domain_to, *user
300 );
301 return Err(PAASServerError::AccessDenied {
302 from: format!("{:?}", request.domain_from.clone()),
303 to: format!("{:?}", request.domain_to.clone()),
304 });
305 }
306
307 let session_valid =
308 match session_storage.session_exists(user.sub.to_string(), request.session_to.clone()) {
309 Ok(valid) => valid,
310 Err(e) => {
311 error!(
312 "Failed to check if session exists: session={:?} {}",
313 request.session_to, *user
314 );
315 return Err(PAASServerError::SessionError(Box::new(e)));
316 }
317 };
318
319 if !session_valid {
320 warn!(
321 "Invalid session: session={:?} {}",
322 request.session_to, *user
323 );
324 return Err(PAASServerError::InvalidSession(
325 "Target session not owned by user".to_string(),
326 ));
327 }
328
329 let transcryption_info = pep_system.transcryption_info(
330 &request.domain_from,
331 &request.domain_to,
332 &request.session_from,
333 &request.session_to,
334 );
335
336 let result = pep_system.transcrypt(&request.encrypted, &transcryption_info);
337
338 info!(
339 "Transcrypted: domain={:?}→{:?} session={:?}→{:?} {}",
340 request.domain_from, request.domain_to, request.session_from, request.session_to, *user
341 );
342
343 Ok(HttpResponse::Ok().json(TranscryptionResponse { result }))
344}
345
346pub async fn transcrypt_batch<T>(
347 item: web::Json<TranscryptionBatchRequest<T>>,
348 access_rules: Data<AccessRules>,
349 session_storage: Data<Box<dyn SessionStorage>>,
350 pep_system: Data<DistributedTranscryptor>,
351 user: web::ReqData<AuthInfo>,
352) -> Result<HttpResponse, PAASServerError>
353where
354 T: Transcryptable + Serialize + HasStructure + Clone,
355{
356 let session_storage = session_storage.get_ref();
357 let request = item.into_inner();
358 let batch_size = request.encrypted.len();
359
360 debug!(
361 "Processing transcrypt batch request: domain={:?}→{:?} session={:?}→{:?} count={} {}",
362 request.domain_from,
363 request.domain_to,
364 request.session_from,
365 request.session_to,
366 batch_size,
367 *user
368 );
369
370 if !access_rules.has_access(&user, &request.domain_from, &request.domain_to) {
371 warn!(
372 "Access denied: domain={:?}→{:?} {}",
373 request.domain_from, request.domain_to, *user
374 );
375 return Err(PAASServerError::AccessDenied {
376 from: format!("{:?}", request.domain_from.clone()),
377 to: format!("{:?}", request.domain_to.clone()),
378 });
379 }
380
381 let session_valid =
382 match session_storage.session_exists(user.sub.to_string(), request.session_to.clone()) {
383 Ok(valid) => valid,
384 Err(e) => {
385 error!(
386 "Failed to check if session exists: session={:?} {}",
387 request.session_to, *user
388 );
389 return Err(PAASServerError::SessionError(Box::new(e)));
390 }
391 };
392
393 if !session_valid {
394 warn!(
395 "Invalid session: session={:?} {}",
396 request.session_to, *user
397 );
398 return Err(PAASServerError::InvalidSession(
399 "Target session not owned by user".to_string(),
400 ));
401 }
402
403 let transcryption_info = pep_system.transcryption_info(
404 &request.domain_from,
405 &request.domain_to,
406 &request.session_from,
407 &request.session_to,
408 );
409
410 let mut rng = rand::rng();
411 let msg_out = pep_system.transcrypt_batch(
412 &mut request.encrypted.into_boxed_slice(),
413 &transcryption_info,
414 &mut rng,
415 )?;
416
417 info!(
418 "Transcrypted: domain={:?}→{:?} session={:?}→{:?} count={} {}",
419 request.domain_from,
420 request.domain_to,
421 request.session_from,
422 request.session_to,
423 batch_size,
424 *user
425 );
426
427 Ok(HttpResponse::Ok().json(TranscryptionBatchResponse {
428 result: Vec::from(msg_out),
429 }))
430}