cloudiful_redactor/
service.rs1use anyhow::{Context, Result};
2
3use crate::{
4 InputKind, RedactionArtifact, RedactionSession, Redactor, RestoreResult,
5 decrypt_session_from_str, encrypt_session_to_string, ensure_restore_valid,
6 inspect_encrypted_session,
7};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct EncryptedRedactionArtifact {
11 pub artifact: RedactionArtifact,
12 pub encrypted_session: String,
13 pub session_summary: crate::SessionSummary,
14}
15
16pub fn redact_text_artifact(
17 redactor: &Redactor,
18 text: &str,
19 input_kind: InputKind,
20) -> Result<RedactionArtifact> {
21 redactor
22 .redact_artifact_with_input_kind(text, input_kind)
23 .map_err(anyhow::Error::new)
24}
25
26pub fn redact_text_artifact_with_source(
27 redactor: &Redactor,
28 text: &str,
29 input_kind: InputKind,
30 source_path: &str,
31) -> Result<RedactionArtifact> {
32 redactor
33 .redact_artifact_with_input_kind_and_source(text, input_kind, Some(source_path))
34 .map_err(anyhow::Error::new)
35}
36
37pub fn redact_text_with_encrypted_session(
38 redactor: &Redactor,
39 text: &str,
40 input_kind: InputKind,
41 passphrase: &str,
42) -> Result<EncryptedRedactionArtifact> {
43 let artifact =
44 redact_text_artifact(redactor, text, input_kind).context("failed to redact text input")?;
45 let encrypted_session = encrypt_session_to_string(&artifact.session, passphrase)
46 .context("failed to encrypt redaction session")?;
47 let session_summary = inspect_encrypted_session(&encrypted_session)
48 .context("failed to inspect encrypted session")?;
49
50 Ok(EncryptedRedactionArtifact {
51 artifact,
52 encrypted_session,
53 session_summary,
54 })
55}
56
57pub fn redact_text_with_encrypted_session_and_source(
58 redactor: &Redactor,
59 text: &str,
60 input_kind: InputKind,
61 source_path: &str,
62 passphrase: &str,
63) -> Result<EncryptedRedactionArtifact> {
64 let artifact = redact_text_artifact_with_source(redactor, text, input_kind, source_path)
65 .context("failed to redact text input")?;
66 let encrypted_session = encrypt_session_to_string(&artifact.session, passphrase)
67 .context("failed to encrypt redaction session")?;
68 let session_summary = inspect_encrypted_session(&encrypted_session)
69 .context("failed to inspect encrypted session")?;
70
71 Ok(EncryptedRedactionArtifact {
72 artifact,
73 encrypted_session,
74 session_summary,
75 })
76}
77
78pub fn decrypt_redaction_session(
79 encrypted_session: &str,
80 passphrase: &str,
81) -> Result<RedactionSession> {
82 decrypt_session_from_str(encrypted_session, passphrase)
83 .context("failed to decrypt provided session")
84}
85
86pub fn restore_text_from_encrypted_session(
87 redactor: &Redactor,
88 text: &str,
89 encrypted_session: &str,
90 passphrase: &str,
91) -> Result<RestoreResult> {
92 let session = decrypt_redaction_session(encrypted_session, passphrase)?;
93 let restored = redactor.restore_text(text, &session);
94 ensure_restore_valid(&restored)?;
95 Ok(restored)
96}
97
98#[cfg(test)]
99mod tests {
100 use super::{
101 redact_text_artifact, redact_text_with_encrypted_session,
102 restore_text_from_encrypted_session,
103 };
104 use crate::{InputKind, RedactionPolicy, RedactorBuilder};
105 use crate::types::FindingKind;
106
107 fn full_redactor() -> crate::Redactor {
108 RedactorBuilder::new()
109 .with_redaction_policy(
110 RedactionPolicy::default()
111 .with_kind(FindingKind::Domain, true)
112 .with_kind(FindingKind::Secret, true)
113 .with_kind(FindingKind::Url, true),
114 )
115 .build()
116 }
117
118 #[test]
119 fn encrypted_redaction_matches_plain_artifact_output() {
120 let redactor = full_redactor();
121 let text = "host=service.example.com secret=EJ2QEVC6AKELW0k2kkVY4NgGKONC";
122 let plain = redact_text_artifact(&redactor, text, InputKind::Text).expect("plain");
123 let encrypted =
124 redact_text_with_encrypted_session(&redactor, text, InputKind::Text, "pass")
125 .expect("encrypted");
126
127 assert_eq!(
128 encrypted.artifact.result.redacted_text,
129 plain.result.redacted_text
130 );
131 assert_eq!(
132 encrypted.artifact.session.redacted_text,
133 plain.session.redacted_text
134 );
135 }
136
137 #[test]
138 fn encrypted_session_restore_round_trips() {
139 let redactor = full_redactor();
140 let text = "host=service.example.com";
141 let encrypted =
142 redact_text_with_encrypted_session(&redactor, text, InputKind::Text, "pass")
143 .expect("encrypted");
144
145 let restored = restore_text_from_encrypted_session(
146 &redactor,
147 &encrypted.artifact.result.redacted_text,
148 &encrypted.encrypted_session,
149 "pass",
150 )
151 .expect("restore");
152
153 assert_eq!(restored.restored_text, text);
154 }
155}