redaction.rs (3448B)
1 use std::fs; 2 3 use harvestcircle_application::IdentityRepository; 4 use harvestcircle_domain::{ 5 IdentityCreatedAt, LocalKeyringBinding, NostrIdentity, NostrIdentityReference, PublicKey, 6 SignerAvailability, UnixTimestamp, 7 }; 8 use harvestcircle_storage::Database; 9 use radroots_runtime_paths::{ 10 InstanceId, RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPathResolver, 11 RadrootsPlatform, RuntimeContext, RuntimeContextBootstrap, RuntimeContextSource, ServiceId, 12 }; 13 use radroots_service_sqlite::MigrationBuildIdentity; 14 use tempfile::{TempDir, tempdir_in}; 15 16 fn tempdir() -> std::io::Result<TempDir> { 17 tempdir_in(std::env::temp_dir().canonicalize()?) 18 } 19 20 const SECRET_HEX: &str = "1111111111111111111111111111111111111111111111111111111111111111"; 21 const SECRET_NSEC: &str = "nsec1vl029mgpspedva04g90vltkh6fvh240zqtv9k0t9af8935ke9laqsnlfe5"; 22 fn assert_redacted(bytes: &[u8]) { 23 assert!( 24 !bytes 25 .windows(SECRET_HEX.len()) 26 .any(|value| value == SECRET_HEX.as_bytes()) 27 ); 28 assert!( 29 !bytes 30 .windows(SECRET_NSEC.len()) 31 .any(|value| value == SECRET_NSEC.as_bytes()) 32 ); 33 assert!(!bytes.windows(5).any(|value| value == b"nsec1")); 34 } 35 36 fn runtime_context(directory: &TempDir) -> RuntimeContext { 37 let context = RuntimeContext::resolve( 38 &RadrootsPathResolver::new( 39 RadrootsPlatform::current(), 40 RadrootsHostEnvironment::default(), 41 ), 42 RuntimeContextBootstrap::new( 43 RadrootsPathProfile::RepoLocal, 44 Some( 45 directory 46 .path() 47 .canonicalize() 48 .expect("canonical directory"), 49 ), 50 RuntimeContextSource::BootstrapCli, 51 RuntimeContextSource::SafeDefault, 52 ) 53 .expect("bootstrap"), 54 ServiceId::new("harvestcircle").expect("service"), 55 InstanceId::new("desktop").expect("instance"), 56 ) 57 .expect("runtime context"); 58 fs::create_dir_all(directory.path().join("data")).expect("state root"); 59 context 60 } 61 62 fn build_identity() -> MigrationBuildIdentity { 63 MigrationBuildIdentity::new( 64 "0.1.0-alpha", 65 "1111111111111111111111111111111111111111", 66 "2222222222222222222222222222222222222222", 67 "1.97.1", 68 "test", 69 "test", 70 1, 71 1, 72 1, 73 1, 74 1, 75 ) 76 .expect("build identity") 77 } 78 79 #[tokio::test] 80 async fn redaction_guards_sqlite_schema_and_non_secret_records() { 81 let directory = tempdir().expect("directory"); 82 let context = runtime_context(&directory); 83 let path = context.paths().state().join("state.sqlite"); 84 { 85 let database = Database::open(&context, 1, 1, &build_identity()) 86 .await 87 .expect("database"); 88 let public_key = PublicKey::from_bytes([7; 32]).expect("valid public key"); 89 let identity = NostrIdentity::new( 90 NostrIdentityReference::derive(public_key).expect("identity"), 91 LocalKeyringBinding::new(public_key, SignerAvailability::Available), 92 None, 93 IdentityCreatedAt::new(UnixTimestamp::from_seconds(1).expect("time")), 94 None, 95 ) 96 .expect("identity"); 97 database.insert_identity(&identity).await.expect("identity"); 98 database.close().await.expect("close"); 99 } 100 assert_redacted(&fs::read(path).expect("database bytes")); 101 }