app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

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 }