Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fwd compat from 0.4.4 integration test #131

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
22 changes: 18 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
- name: Rust Toolchain
run: |
rustup toolchain install ${{ matrix.toolchain }} --profile minimal --no-self-update
rustup default ${{ matrix.toolchain }}

- name: Install vcpkg packages
if: matrix.os == 'windows-latest'
Expand All @@ -41,6 +41,20 @@ jobs:
manifest-dir: ${{ github.workspace }}/.github/manifest
github-binarycache: true

- name: Install lair-keystore-0.4.4 for fwd compat test Windows
if: matrix.os == 'windows-latest'
run: |-
$env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows-release\lib"
cargo install [email protected] --debug

- name: Install lair-keystore-0.4.4 for fwd compat test
if: matrix.os != 'windows-latest'
run: cargo install [email protected] --debug

- name: Rename lair-keystore to include version
shell: bash
run: mv $(which lair-keystore){,-0.4.4}

- name: Make Test Windows
if: matrix.os == 'windows-latest'
run: |-
Expand Down
6 changes: 6 additions & 0 deletions crates/lair_keystore/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mod tests {
mod common;
mod fwd_compat_0_4_4;
mod migrate_unencrypted;
mod server_test;
}
230 changes: 230 additions & 0 deletions crates/lair_keystore/tests/tests/fwd_compat_0_4_4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
use lair_keystore::dependencies::*;
use lair_keystore_api::prelude::*;
use std::sync::Arc;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};

#[cfg(not(windows))]
const NAME: &str = "lair-keystore-0.4.4";

#[cfg(windows)]
const NAME: &str = "lair-keystore-0.4.4.exe";

const PASSPHRASE: &[u8] = b"passphrase";

const TAG1: &str = "TAG1";
const TAG2: &str = "TAG2";

#[tokio::test(flavor = "multi_thread")]
async fn fwd_compat_0_4_4() {
let tmpdir = tempdir::TempDir::new("lair_fwd_044").unwrap();

println!("{tmpdir:?}");

// -- make sure we have the correct 0.4.4 version avaliable -- //

let mut cmd = tokio::process::Command::new(NAME);

cmd.kill_on_drop(true).arg("--version");

eprintln!("{cmd:?}");

let ver = cmd
.output()
.await
.expect("please ensure above command is on the PATH");

assert!(ver.status.success());
assert_eq!(b"lair_keystore 0.4.4\n", ver.stdout.as_slice());

// -- initialize the 0.4.4 keystore -- //

let mut cmd = tokio::process::Command::new(NAME);

cmd.kill_on_drop(true)
.arg("--lair-root")
.arg(tmpdir.path())
.arg("init")
.arg("--piped")
.stdin(std::process::Stdio::piped());

eprintln!("{cmd:?}");

let mut init = cmd.spawn().unwrap();
let mut stdin = init.stdin.take().unwrap();
stdin.write_all(PASSPHRASE).await.unwrap();
stdin.shutdown().await.unwrap();
drop(stdin);

let init = init.wait_with_output().await.unwrap();

assert!(init.status.success());
println!("{}", String::from_utf8_lossy(init.stdout.as_slice()));

// -- fetch the connection string -- //

let mut cmd = tokio::process::Command::new(NAME);

cmd.kill_on_drop(true)
.arg("--lair-root")
.arg(tmpdir.path())
.arg("url");

eprintln!("{cmd:?}");

let s_url = cmd
.output()
.await
.expect("please ensure above command is on the PATH");

assert!(s_url.status.success());
let s_url = String::from_utf8_lossy(s_url.stdout.as_slice()).to_string();
let s_url = url::Url::parse(&s_url).unwrap();

println!("s_url: {s_url}");

// -- run the actual server -- //

let mut cmd = tokio::process::Command::new(NAME);

cmd.kill_on_drop(true)
.arg("--lair-root")
.arg(tmpdir.path())
.arg("server")
.arg("--piped")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped());

eprintln!("{cmd:?}");

let mut server = cmd.spawn().unwrap();
let mut stdin = server.stdin.take().unwrap();
stdin.write_all(PASSPHRASE).await.unwrap();
stdin.shutdown().await.unwrap();
drop(stdin);

let mut server_lines =
tokio::io::BufReader::new(server.stdout.take().unwrap()).lines();

tokio::time::timeout(std::time::Duration::from_secs(10), async {
loop {
let line = server_lines.next_line().await.unwrap().unwrap();
println!("-:=:- {line}");
if line.contains("lair-keystore running") {
break;
}
}
})
.await
.unwrap();

// -- connect a client and insert data into the store -- //

let client044 = lair_keystore_api::ipc_keystore::ipc_keystore_connect(
s_url.clone(),
PASSPHRASE,
)
.await
.unwrap();

let _seed_info_ref =
client044.new_seed(TAG1.into(), None, true).await.unwrap();

let _wka_cert = client044.new_wka_tls_cert(TAG2.into()).await.unwrap();

// -- shut down the 044 client and server -- //

client044.shutdown().await.unwrap();
drop(client044);

// give windows a chance to sync to disk
tokio::time::sleep(std::time::Duration::from_secs(5)).await;

server.kill().await.unwrap();
drop(server);

// -- run the new server using the 044 store -- //

let mut config_path = tmpdir.path().to_owned();
config_path.push("lair-keystore-config.yaml");
let config = tokio::fs::read(&config_path).await.unwrap();

println!("{}", String::from_utf8_lossy(&config));

let config = LairServerConfigInner::from_bytes(&config).unwrap();

lair_keystore::server::StandaloneServer::new(Arc::new(config))
.await
.unwrap()
.run(PASSPHRASE)
.await
.unwrap();

// -- connect a client to the new server and check functionality -- //

let client = lair_keystore_api::ipc_keystore::ipc_keystore_connect(
s_url.clone(),
PASSPHRASE,
)
.await
.unwrap();

let entry_list = client.list_entries().await.unwrap();

assert_eq!(2, entry_list.len());

for entry in entry_list {
match entry {
LairEntryInfo::Seed { tag, .. } => {
assert_eq!(TAG1, &*tag);
}
LairEntryInfo::WkaTlsCert { tag, .. } => {
assert_eq!(TAG2, &*tag);
}
oth => panic!("unexpected: {:?}", oth),
}
}

let entry = match client.get_entry(TAG1.into()).await.unwrap() {
LairEntryInfo::Seed { seed_info, .. } => seed_info,
_ => panic!(),
};

let sig = client
.sign_by_pub_key(
entry.ed25519_pub_key.clone(),
None,
b"hello".to_vec().into(),
)
.await
.unwrap();
assert!(entry
.ed25519_pub_key
.verify_detached(sig, &b"hello"[..])
.await
.unwrap());

// secretbox encrypt some data
let (nonce, cipher) = client
.secretbox_xsalsa_by_tag(TAG1.into(), None, b"hello".to_vec().into())
.await
.unwrap();

// make sure we can decrypt our own message
let msg = client
.secretbox_xsalsa_open_by_tag(TAG1.into(), None, nonce, cipher)
.await
.unwrap();

assert_eq!(b"hello", &*msg);

// try exporting the seed (just to ourselves)
let _ = client
.export_seed_by_tag(
TAG1.into(),
entry.x25519_pub_key.clone(),
entry.x25519_pub_key.clone(),
None,
)
.await
.unwrap();
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use common::{connect_with_config, create_config};
use super::common::{connect_with_config, create_config};
use lair_keystore_api::dependencies::{sodoken, tokio};

mod common;

#[cfg(not(windows))] // No encryption on Windows, ignore this test
#[tokio::test(flavor = "multi_thread")]
async fn migrate_unencrypted() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use common::connect;
use super::common::connect;
use lair_keystore::dependencies::*;
use lair_keystore_api::prelude::*;

mod common;

#[tokio::test(flavor = "multi_thread")]
async fn server_test_happy_path() {
let tmpdir = tempdir::TempDir::new("lair keystore test").unwrap();
Expand Down
Loading