mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-18 21:34:37 +03:00
chore(doc): Docs for rosenpass::{config, cli} (#560)
Some checks are pending
Nix / Build i686-linux.default (push) Blocked by required conditions
Nix / Build i686-linux.rosenpass (push) Waiting to run
Nix / Build i686-linux.rosenpass-oci-image (push) Blocked by required conditions
Nix / Run Nix checks on i686-linux (push) Waiting to run
Nix / Build x86_64-darwin.default (push) Blocked by required conditions
Nix / Build x86_64-darwin.release-package (push) Blocked by required conditions
Nix / Build x86_64-darwin.rosenpass (push) Waiting to run
Nix / Build x86_64-darwin.rp (push) Waiting to run
Nix / Build x86_64-darwin.rosenpass-oci-image (push) Blocked by required conditions
Nix / Run Nix checks on x86_64-darwin (push) Waiting to run
Nix / Build x86_64-linux.default (push) Blocked by required conditions
Nix / Build x86_64-linux.proof-proverif (push) Blocked by required conditions
Nix / Build x86_64-linux.proverif-patched (push) Waiting to run
Nix / Build x86_64-linux.release-package (push) Blocked by required conditions
Nix / Build x86_64-linux.rosenpass (push) Waiting to run
Nix / Build aarch64-linux.rosenpass (push) Waiting to run
Nix / Build aarch64-linux.rp (push) Waiting to run
Nix / Build x86_64-linux.rosenpass-oci-image (push) Blocked by required conditions
Nix / Build aarch64-linux.rosenpass-oci-image (push) Blocked by required conditions
Nix / Build x86_64-linux.rosenpass-static (push) Waiting to run
Nix / Build x86_64-linux.rp-static (push) Waiting to run
Nix / Build x86_64-linux.rosenpass-static-oci-image (push) Blocked by required conditions
Nix / Build x86_64-linux.whitepaper (push) Waiting to run
Nix / Run Nix checks on x86_64-linux (push) Waiting to run
Nix / Upload whitepaper x86_64-linux (push) Waiting to run
QC / prettier (push) Waiting to run
QC / Shellcheck (push) Waiting to run
QC / Rust Format (push) Waiting to run
QC / cargo-bench (push) Waiting to run
QC / mandoc (push) Waiting to run
QC / cargo-audit (push) Waiting to run
QC / cargo-clippy (push) Waiting to run
QC / cargo-doc (push) Waiting to run
QC / cargo-test (macos-13) (push) Waiting to run
QC / cargo-test (ubuntu-latest) (push) Waiting to run
QC / cargo-test-nix-devshell-x86_64-linux (push) Waiting to run
QC / cargo-fuzz (push) Waiting to run
QC / codecov (push) Waiting to run
Regressions / multi-peer (push) Waiting to run
Regressions / boot-race (push) Waiting to run
Some checks are pending
Nix / Build i686-linux.default (push) Blocked by required conditions
Nix / Build i686-linux.rosenpass (push) Waiting to run
Nix / Build i686-linux.rosenpass-oci-image (push) Blocked by required conditions
Nix / Run Nix checks on i686-linux (push) Waiting to run
Nix / Build x86_64-darwin.default (push) Blocked by required conditions
Nix / Build x86_64-darwin.release-package (push) Blocked by required conditions
Nix / Build x86_64-darwin.rosenpass (push) Waiting to run
Nix / Build x86_64-darwin.rp (push) Waiting to run
Nix / Build x86_64-darwin.rosenpass-oci-image (push) Blocked by required conditions
Nix / Run Nix checks on x86_64-darwin (push) Waiting to run
Nix / Build x86_64-linux.default (push) Blocked by required conditions
Nix / Build x86_64-linux.proof-proverif (push) Blocked by required conditions
Nix / Build x86_64-linux.proverif-patched (push) Waiting to run
Nix / Build x86_64-linux.release-package (push) Blocked by required conditions
Nix / Build x86_64-linux.rosenpass (push) Waiting to run
Nix / Build aarch64-linux.rosenpass (push) Waiting to run
Nix / Build aarch64-linux.rp (push) Waiting to run
Nix / Build x86_64-linux.rosenpass-oci-image (push) Blocked by required conditions
Nix / Build aarch64-linux.rosenpass-oci-image (push) Blocked by required conditions
Nix / Build x86_64-linux.rosenpass-static (push) Waiting to run
Nix / Build x86_64-linux.rp-static (push) Waiting to run
Nix / Build x86_64-linux.rosenpass-static-oci-image (push) Blocked by required conditions
Nix / Build x86_64-linux.whitepaper (push) Waiting to run
Nix / Run Nix checks on x86_64-linux (push) Waiting to run
Nix / Upload whitepaper x86_64-linux (push) Waiting to run
QC / prettier (push) Waiting to run
QC / Shellcheck (push) Waiting to run
QC / Rust Format (push) Waiting to run
QC / cargo-bench (push) Waiting to run
QC / mandoc (push) Waiting to run
QC / cargo-audit (push) Waiting to run
QC / cargo-clippy (push) Waiting to run
QC / cargo-doc (push) Waiting to run
QC / cargo-test (macos-13) (push) Waiting to run
QC / cargo-test (ubuntu-latest) (push) Waiting to run
QC / cargo-test-nix-devshell-x86_64-linux (push) Waiting to run
QC / cargo-fuzz (push) Waiting to run
QC / codecov (push) Waiting to run
Regressions / multi-peer (push) Waiting to run
Regressions / boot-race (push) Waiting to run
This commit is contained in:
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::app_server::AppServer;
|
use crate::app_server::AppServer;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
|
||||||
pub struct ApiConfig {
|
pub struct ApiConfig {
|
||||||
/// Where in the file-system to create the unix socket the rosenpass API will be listening for
|
/// Where in the file-system to create the unix socket the rosenpass API will be listening for
|
||||||
/// connections on
|
/// connections on
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
//! Contains the code used to parse command line parameters for rosenpass.
|
||||||
|
//!
|
||||||
|
//! [CliArgs::run] is called by the rosenpass main function and contains the
|
||||||
|
//! bulk of our boostrapping code while the main function just sets up the basic environment
|
||||||
|
|
||||||
use anyhow::{bail, ensure, Context};
|
use anyhow::{bail, ensure, Context};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use rosenpass_cipher_traits::Kem;
|
use rosenpass_cipher_traits::Kem;
|
||||||
@@ -31,15 +36,25 @@ use {
|
|||||||
std::thread,
|
std::thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// enum representing a choice of interface to a WireGuard broker
|
/// How to reach a WireGuard PSK Broker
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BrokerInterface {
|
pub enum BrokerInterface {
|
||||||
|
/// The PSK Broker is listening on a unix socket at the given path
|
||||||
Socket(PathBuf),
|
Socket(PathBuf),
|
||||||
|
/// The PSK Broker broker is already connected to this process; a
|
||||||
|
/// unix socket stream can be reached at the given file descriptor.
|
||||||
|
///
|
||||||
|
/// This is generally used with file descriptor passing.
|
||||||
FileDescriptor(i32),
|
FileDescriptor(i32),
|
||||||
|
/// Create a socketpair(3p), spawn the PSK broker process from within rosenpass,
|
||||||
|
/// and hand one end of the socketpair to the broker process via file
|
||||||
|
/// descriptor passing to the subprocess
|
||||||
SocketPair,
|
SocketPair,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// struct holding all CLI arguments for `clap` crate to parse
|
/// Command line arguments to the Rosenpass binary.
|
||||||
|
///
|
||||||
|
/// Used for parsing with [clap].
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about, arg_required_else_help = true)]
|
#[command(author, version, about, long_about, arg_required_else_help = true)]
|
||||||
pub struct CliArgs {
|
pub struct CliArgs {
|
||||||
@@ -80,6 +95,7 @@ pub struct CliArgs {
|
|||||||
#[arg(short, long, group = "psk-broker-specs")]
|
#[arg(short, long, group = "psk-broker-specs")]
|
||||||
psk_broker_spawn: bool,
|
psk_broker_spawn: bool,
|
||||||
|
|
||||||
|
/// The subcommand to be invoked
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub command: Option<CliCommand>,
|
pub command: Option<CliCommand>,
|
||||||
|
|
||||||
@@ -98,6 +114,10 @@ pub struct CliArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CliArgs {
|
impl CliArgs {
|
||||||
|
/// Apply the command line parameters to the Rosenpass configuration struct
|
||||||
|
///
|
||||||
|
/// Generally the flow of control here is that all the command line parameters
|
||||||
|
/// are merged into the configuration file to avoid much code duplication.
|
||||||
pub fn apply_to_config(&self, _cfg: &mut config::Rosenpass) -> anyhow::Result<()> {
|
pub fn apply_to_config(&self, _cfg: &mut config::Rosenpass) -> anyhow::Result<()> {
|
||||||
#[cfg(feature = "experiment_api")]
|
#[cfg(feature = "experiment_api")]
|
||||||
self.api.apply_to_config(_cfg)?;
|
self.api.apply_to_config(_cfg)?;
|
||||||
@@ -123,9 +143,11 @@ impl CliArgs {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the WireGuard PSK broker interface configured.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the `experiment_api` feature is disabled.
|
||||||
|
|
||||||
#[cfg(feature = "experiment_api")]
|
#[cfg(feature = "experiment_api")]
|
||||||
/// returns the broker interface set by CLI args
|
|
||||||
/// returns `None` if the `experiment_api` feature isn't enabled
|
|
||||||
pub fn get_broker_interface(&self) -> Option<BrokerInterface> {
|
pub fn get_broker_interface(&self) -> Option<BrokerInterface> {
|
||||||
if let Some(path_ref) = self.psk_broker_path.as_ref() {
|
if let Some(path_ref) = self.psk_broker_path.as_ref() {
|
||||||
Some(BrokerInterface::Socket(path_ref.to_path_buf()))
|
Some(BrokerInterface::Socket(path_ref.to_path_buf()))
|
||||||
@@ -138,9 +160,10 @@ impl CliArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the WireGuard PSK broker interface configured.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the `experiment_api` feature is disabled.
|
||||||
#[cfg(not(feature = "experiment_api"))]
|
#[cfg(not(feature = "experiment_api"))]
|
||||||
/// returns the broker interface set by CLI args
|
|
||||||
/// returns `None` if the `experiment_api` feature isn't enabled
|
|
||||||
pub fn get_broker_interface(&self) -> Option<BrokerInterface> {
|
pub fn get_broker_interface(&self) -> Option<BrokerInterface> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -244,15 +267,17 @@ pub enum CliCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CliArgs {
|
impl CliArgs {
|
||||||
/// Runs the command specified via CLI
|
/// Run Rosenpass with the given command line parameters
|
||||||
///
|
///
|
||||||
/// ## TODO
|
/// This contains the bulk of our startup logic with
|
||||||
/// - This method consumes the [`CliCommand`] value. It might be wise to use a reference...
|
/// the main function just setting up the basic environment
|
||||||
|
/// and then calling this function.
|
||||||
pub fn run(
|
pub fn run(
|
||||||
self,
|
self,
|
||||||
broker_interface: Option<BrokerInterface>,
|
broker_interface: Option<BrokerInterface>,
|
||||||
test_helpers: Option<AppServerTest>,
|
test_helpers: Option<AppServerTest>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
// TODO: This method consumes the [`CliCommand`] value. It might be wise to use a reference...
|
||||||
use CliCommand::*;
|
use CliCommand::*;
|
||||||
match &self.command {
|
match &self.command {
|
||||||
Some(GenConfig { config_file, force }) => {
|
Some(GenConfig { config_file, force }) => {
|
||||||
@@ -403,6 +428,7 @@ impl CliArgs {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used by [Self::run] to start the Rosenpass key exchange server
|
||||||
fn event_loop(
|
fn event_loop(
|
||||||
config: config::Rosenpass,
|
config: config::Rosenpass,
|
||||||
broker_interface: Option<BrokerInterface>,
|
broker_interface: Option<BrokerInterface>,
|
||||||
@@ -470,6 +496,19 @@ impl CliArgs {
|
|||||||
srv.event_loop()
|
srv.event_loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create the WireGuard PSK broker to be used by
|
||||||
|
/// [crate::app_server::AppServer].
|
||||||
|
///
|
||||||
|
/// If the `experiment_api`
|
||||||
|
/// feature flag is set, then this communicates with a PSK broker
|
||||||
|
/// running in a different process as configured via
|
||||||
|
/// the `psk_broker_path`, `psk_broker_fd`, and `psk_broker_spawn`
|
||||||
|
/// fields.
|
||||||
|
///
|
||||||
|
/// If the `experiment_api`
|
||||||
|
/// feature flag is not set, then this returns a [NativeUnixBroker],
|
||||||
|
/// sending pre-shared keys directly to WireGuard from within this
|
||||||
|
/// process.
|
||||||
#[cfg(feature = "experiment_api")]
|
#[cfg(feature = "experiment_api")]
|
||||||
fn create_broker(
|
fn create_broker(
|
||||||
broker_interface: Option<BrokerInterface>,
|
broker_interface: Option<BrokerInterface>,
|
||||||
@@ -485,6 +524,19 @@ impl CliArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create the WireGuard PSK broker to be used by
|
||||||
|
/// [crate::app_server::AppServer].
|
||||||
|
///
|
||||||
|
/// If the `experiment_api`
|
||||||
|
/// feature flag is set, then this communicates with a PSK broker
|
||||||
|
/// running in a different process as configured via
|
||||||
|
/// the `psk_broker_path`, `psk_broker_fd`, and `psk_broker_spawn`
|
||||||
|
/// fields.
|
||||||
|
///
|
||||||
|
/// If the `experiment_api`
|
||||||
|
/// feature flag is not set, then this returns a [NativeUnixBroker],
|
||||||
|
/// sending pre-shared keys directly to WireGuard from within this
|
||||||
|
/// process.
|
||||||
#[cfg(not(feature = "experiment_api"))]
|
#[cfg(not(feature = "experiment_api"))]
|
||||||
fn create_broker(
|
fn create_broker(
|
||||||
_broker_interface: Option<BrokerInterface>,
|
_broker_interface: Option<BrokerInterface>,
|
||||||
@@ -492,6 +544,10 @@ impl CliArgs {
|
|||||||
Ok(Box::new(NativeUnixBroker::new()))
|
Ok(Box::new(NativeUnixBroker::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used by [Self::create_broker] if the `experiment_api` is configured
|
||||||
|
/// to set up the connection with the PSK broker process as configured
|
||||||
|
/// via the `psk_broker_path`, `psk_broker_fd`, and `psk_broker_spawn`
|
||||||
|
/// fields.
|
||||||
#[cfg(feature = "experiment_api")]
|
#[cfg(feature = "experiment_api")]
|
||||||
fn get_broker_socket(broker_interface: BrokerInterface) -> Result<UnixStream, anyhow::Error> {
|
fn get_broker_socket(broker_interface: BrokerInterface) -> Result<UnixStream, anyhow::Error> {
|
||||||
// Connect to the psk broker unix socket if one was specified
|
// Connect to the psk broker unix socket if one was specified
|
||||||
@@ -549,7 +605,7 @@ impl CliArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// generate secret and public keys, store in files according to the paths passed as arguments
|
/// generate secret and public keys, store in files according to the paths passed as arguments
|
||||||
fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
|
pub fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
|
||||||
let mut ssk = crate::protocol::SSk::random();
|
let mut ssk = crate::protocol::SSk::random();
|
||||||
let mut spk = crate::protocol::SPk::random();
|
let mut spk = crate::protocol::SPk::random();
|
||||||
StaticKem::keygen(ssk.secret_mut(), spk.deref_mut())?;
|
StaticKem::keygen(ssk.secret_mut(), spk.deref_mut())?;
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
//! [`Rosenpass`] which holds such a configuration.
|
//! [`Rosenpass`] which holds such a configuration.
|
||||||
//!
|
//!
|
||||||
//! ## TODO
|
//! ## TODO
|
||||||
//! - support `~` in <https://github.com/rosenpass/rosenpass/issues/237>
|
//! - TODO: support `~` in <https://github.com/rosenpass/rosenpass/issues/237>
|
||||||
//! - provide tooling to create config file from shell <https://github.com/rosenpass/rosenpass/issues/247>
|
//! - TODO: provide tooling to create config file from shell <https://github.com/rosenpass/rosenpass/issues/247>
|
||||||
|
|
||||||
use crate::protocol::{SPk, SSk};
|
use crate::protocol::{SPk, SSk};
|
||||||
use rosenpass_util::file::LoadValue;
|
use rosenpass_util::file::LoadValue;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -31,7 +32,10 @@ fn empty_api_config() -> crate::api::config::ApiConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
/// Configuration for the Rosenpass key exchange
|
||||||
|
///
|
||||||
|
/// i.e. configuration for the `rosenpass exchange` and `rosenpass exchange-config` commands
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct Rosenpass {
|
pub struct Rosenpass {
|
||||||
// TODO: Raise error if secret key or public key alone is set during deserialization
|
// TODO: Raise error if secret key or public key alone is set during deserialization
|
||||||
// SEE: https://github.com/serde-rs/serde/issues/2793
|
// SEE: https://github.com/serde-rs/serde/issues/2793
|
||||||
@@ -46,7 +50,10 @@ pub struct Rosenpass {
|
|||||||
/// list of [`SocketAddr`] to listen on
|
/// list of [`SocketAddr`] to listen on
|
||||||
///
|
///
|
||||||
/// Examples:
|
/// Examples:
|
||||||
/// - `0.0.0.0:123`
|
///
|
||||||
|
/// - `0.0.0.0:123` – Listen on any interface using IPv4, port 123
|
||||||
|
/// - `[::1]:1234` – Listen on IPv6 localhost, port 1234
|
||||||
|
/// - `[::]:4476` – Listen on any IPv4 or IPv6 interface, port 4476
|
||||||
pub listen: Vec<SocketAddr>,
|
pub listen: Vec<SocketAddr>,
|
||||||
|
|
||||||
/// log verbosity
|
/// log verbosity
|
||||||
@@ -68,6 +75,7 @@ pub struct Rosenpass {
|
|||||||
pub config_file_path: PathBuf,
|
pub config_file_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Public key and secret key locations.
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
||||||
pub struct Keypair {
|
pub struct Keypair {
|
||||||
/// path to the public key file
|
/// path to the public key file
|
||||||
@@ -78,6 +86,7 @@ pub struct Keypair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Keypair {
|
impl Keypair {
|
||||||
|
/// Construct a keypair from its fields
|
||||||
pub fn new<Pk: AsRef<Path>, Sk: AsRef<Path>>(public_key: Pk, secret_key: Sk) -> Self {
|
pub fn new<Pk: AsRef<Path>, Sk: AsRef<Path>>(public_key: Pk, secret_key: Sk) -> Self {
|
||||||
let public_key = public_key.as_ref().to_path_buf();
|
let public_key = public_key.as_ref().to_path_buf();
|
||||||
let secret_key = secret_key.as_ref().to_path_buf();
|
let secret_key = secret_key.as_ref().to_path_buf();
|
||||||
@@ -88,62 +97,72 @@ impl Keypair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## TODO
|
/// Level of verbosity for [crate::app_server::AppServer]
|
||||||
/// - replace this type with [`log::LevelFilter`], also see <https://github.com/rosenpass/rosenpass/pull/246>
|
///
|
||||||
|
/// The value of the field [crate::app_server::AppServer::verbosity]. See the field documentation
|
||||||
|
/// for details.
|
||||||
|
///
|
||||||
|
/// - TODO: replace this type with [`log::LevelFilter`], also see <https://github.com/rosenpass/rosenpass/pull/246>
|
||||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone)]
|
||||||
pub enum Verbosity {
|
pub enum Verbosity {
|
||||||
Quiet,
|
Quiet,
|
||||||
Verbose,
|
Verbose,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## TODO
|
/// Configuration data for a single Rosenpass peer
|
||||||
/// - examples
|
|
||||||
/// - documentation
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct RosenpassPeer {
|
pub struct RosenpassPeer {
|
||||||
/// path to the public key of the peer
|
/// path to the public key of the peer
|
||||||
pub public_key: PathBuf,
|
pub public_key: PathBuf,
|
||||||
|
|
||||||
/// ## TODO
|
/// The hostname and port to connect to
|
||||||
/// - documentation
|
///
|
||||||
|
/// Can be a
|
||||||
|
///
|
||||||
|
/// - hostname and port, e.g. `localhost:8876` or `rosenpass.eu:1427`
|
||||||
|
/// - IPv4 address and port, e.g. `1.2.3.4:7764`
|
||||||
|
/// - IPv6 address and port, e.g. `[fe80::24]:7890`
|
||||||
pub endpoint: Option<String>,
|
pub endpoint: Option<String>,
|
||||||
|
|
||||||
/// path to the pre-shared key with the peer
|
/// path to the pre-shared key shared with the peer
|
||||||
///
|
///
|
||||||
/// NOTE: this item can be skipped in the config if you do not use a pre-shared key with the peer
|
/// NOTE: this item can be skipped in the config if you do not use a pre-shared key with the peer
|
||||||
pub pre_shared_key: Option<PathBuf>,
|
pub pre_shared_key: Option<PathBuf>,
|
||||||
|
|
||||||
/// ## TODO
|
/// If this field is set to a path, the Rosenpass will write the exchanged symmetric keys
|
||||||
/// - documentation
|
/// to the given file and write a notification to standard out to let the calling application
|
||||||
|
/// know that a new key was exchanged
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub key_out: Option<PathBuf>,
|
pub key_out: Option<PathBuf>,
|
||||||
|
|
||||||
/// ## TODO
|
/// Information for supplying exchanged keys directly to WireGuard
|
||||||
/// - documentation
|
|
||||||
/// - make this field only available on binary builds, not on library builds <https://github.com/rosenpass/rosenpass/issues/249>
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub wg: Option<WireGuard>,
|
pub wg: Option<WireGuard>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## TODO
|
/// Information for supplying exchanged keys directly to WireGuard
|
||||||
/// - documentation
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct WireGuard {
|
pub struct WireGuard {
|
||||||
/// ## TODO
|
/// Name of the WireGuard interface to supply with pre-shared keys generated by the Rosenpass
|
||||||
/// - documentation
|
/// key exchange
|
||||||
pub device: String,
|
pub device: String,
|
||||||
|
|
||||||
/// ## TODO
|
/// WireGuard public key of the peer to supply with pre-shared keys
|
||||||
/// - documentation
|
|
||||||
pub peer: String,
|
pub peer: String,
|
||||||
|
|
||||||
/// ## TODO
|
/// Extra parameters passed to the `wg` command
|
||||||
/// - documentation
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub extra_params: Vec<String>,
|
pub extra_params: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Rosenpass {
|
impl Default for Rosenpass {
|
||||||
|
/// Generate an empty configuration
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_new.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::empty()
|
Self::empty()
|
||||||
}
|
}
|
||||||
@@ -156,8 +175,15 @@ impl Rosenpass {
|
|||||||
/// checked whether they even exist.
|
/// checked whether they even exist.
|
||||||
///
|
///
|
||||||
/// ## TODO
|
/// ## TODO
|
||||||
|
///
|
||||||
/// - consider using a different algorithm to determine home directory – the below one may
|
/// - consider using a different algorithm to determine home directory – the below one may
|
||||||
/// behave unexpectedly on Windows
|
/// behave unexpectedly on Windows
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_store.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn load<P: AsRef<Path>>(p: P) -> anyhow::Result<Self> {
|
pub fn load<P: AsRef<Path>>(p: P) -> anyhow::Result<Self> {
|
||||||
// read file and deserialize
|
// read file and deserialize
|
||||||
let mut config: Self = toml::from_str(&fs::read_to_string(&p)?)?;
|
let mut config: Self = toml::from_str(&fs::read_to_string(&p)?)?;
|
||||||
@@ -185,7 +211,13 @@ impl Rosenpass {
|
|||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a config to a file
|
/// Encode a configuration object as toml and write it to a file
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_store.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn store<P: AsRef<Path>>(&self, p: P) -> anyhow::Result<()> {
|
pub fn store<P: AsRef<Path>>(&self, p: P) -> anyhow::Result<()> {
|
||||||
let serialized_config =
|
let serialized_config =
|
||||||
toml::to_string_pretty(&self).expect("unable to serialize the default config");
|
toml::to_string_pretty(&self).expect("unable to serialize the default config");
|
||||||
@@ -194,6 +226,12 @@ impl Rosenpass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Commit the configuration to where it came from, overwriting the original file
|
/// Commit the configuration to where it came from, overwriting the original file
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_store.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn commit(&self) -> anyhow::Result<()> {
|
pub fn commit(&self) -> anyhow::Result<()> {
|
||||||
let mut f = fopen_w(&self.config_file_path, Visibility::Public)?;
|
let mut f = fopen_w(&self.config_file_path, Visibility::Public)?;
|
||||||
f.write_all(toml::to_string_pretty(&self)?.as_bytes())?;
|
f.write_all(toml::to_string_pretty(&self)?.as_bytes())?;
|
||||||
@@ -201,13 +239,21 @@ impl Rosenpass {
|
|||||||
self.store(&self.config_file_path)
|
self.store(&self.config_file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply the configuration in this object to the given [crate::app_server::AppServer]
|
||||||
pub fn apply_to_app_server(&self, _srv: &mut AppServer) -> anyhow::Result<()> {
|
pub fn apply_to_app_server(&self, _srv: &mut AppServer) -> anyhow::Result<()> {
|
||||||
#[cfg(feature = "experiment_api")]
|
#[cfg(feature = "experiment_api")]
|
||||||
self.api.apply_to_app_server(_srv)?;
|
self.api.apply_to_app_server(_srv)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate a configuration
|
/// Check that the configuration is sound, ensuring
|
||||||
|
/// for instance that the referenced files exist
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_validate.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn validate(&self) -> anyhow::Result<()> {
|
pub fn validate(&self) -> anyhow::Result<()> {
|
||||||
if let Some(ref keypair) = self.keypair {
|
if let Some(ref keypair) = self.keypair {
|
||||||
// check the public key file exists
|
// check the public key file exists
|
||||||
@@ -284,6 +330,21 @@ impl Rosenpass {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that the configuration is useful given the feature set Rosenpass was compiled with
|
||||||
|
/// and the configuration values.
|
||||||
|
///
|
||||||
|
/// This was introduced when we introduced a unix-socket API feature allowing the server
|
||||||
|
/// keypair to be supplied via the API; in this process we also made [Self::keypair] optional.
|
||||||
|
/// With respect to this particular feature, this function ensures that [Self::keypair] is set
|
||||||
|
/// when Rosenpass is compiles without the `experiment_api` flag. When `experiment_api` is
|
||||||
|
/// used, the function ensures that [Self::keypair] is only `None`, if the Rosenpass API is
|
||||||
|
/// enabled in the configuration.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_validate.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn check_usefullness(&self) -> anyhow::Result<()> {
|
pub fn check_usefullness(&self) -> anyhow::Result<()> {
|
||||||
#[cfg(not(feature = "experiment_api"))]
|
#[cfg(not(feature = "experiment_api"))]
|
||||||
ensure!(self.keypair.is_some(), "Server keypair missing.");
|
ensure!(self.keypair.is_some(), "Server keypair missing.");
|
||||||
@@ -299,15 +360,38 @@ impl Rosenpass {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produce an empty confuguration
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_new.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::new(None)
|
Self::new(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produce configuration from the keypair
|
||||||
|
///
|
||||||
|
/// Shorthand for calling [Self::new] with Some([Keypair]::new(sk, pk)).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_new.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn from_sk_pk<Sk: AsRef<Path>, Pk: AsRef<Path>>(sk: Sk, pk: Pk) -> Self {
|
pub fn from_sk_pk<Sk: AsRef<Path>, Pk: AsRef<Path>>(sk: Sk, pk: Pk) -> Self {
|
||||||
Self::new(Some(Keypair::new(pk, sk)))
|
Self::new(Some(Keypair::new(pk, sk)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new configuration
|
/// Initialize a minimal configuration with the [Self::keypair] field supplied
|
||||||
|
/// as a parameter
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_new.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn new(keypair: Option<Keypair>) -> Self {
|
pub fn new(keypair: Option<Keypair>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
keypair,
|
keypair,
|
||||||
@@ -321,6 +405,14 @@ impl Rosenpass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add IPv4 __and__ IPv6 IF_ANY address to the listen interfaces
|
/// Add IPv4 __and__ IPv6 IF_ANY address to the listen interfaces
|
||||||
|
///
|
||||||
|
/// I.e. listen on any interface.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_add_if_any.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn add_if_any(&mut self, port: u16) {
|
pub fn add_if_any(&mut self, port: u16) {
|
||||||
let ipv4_any = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port));
|
let ipv4_any = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port));
|
||||||
let ipv6_any = SocketAddr::V6(SocketAddrV6::new(
|
let ipv6_any = SocketAddr::V6(SocketAddrV6::new(
|
||||||
@@ -333,8 +425,20 @@ impl Rosenpass {
|
|||||||
self.listen.push(ipv6_any);
|
self.listen.push(ipv6_any);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// from chaotic args
|
/// Parser for the old, IP style grammar.
|
||||||
/// Quest: the grammar is undecideable, what do we do here?
|
///
|
||||||
|
/// See out manual page rosenpass-exchange(1) on details about the grammar.
|
||||||
|
///
|
||||||
|
/// This function parses the grammar and turns it into an instance of the configuration
|
||||||
|
/// struct.
|
||||||
|
///
|
||||||
|
/// TODO: the grammar is undecidable, what do we do here?
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
#[doc = "```ignore"]
|
||||||
|
#[doc = include_str!("../tests/config_Rosenpass_parse_args_simple.rs")]
|
||||||
|
#[doc = "```"]
|
||||||
pub fn parse_args(args: Vec<String>) -> anyhow::Result<Self> {
|
pub fn parse_args(args: Vec<String>) -> anyhow::Result<Self> {
|
||||||
let mut config = Self::new(Some(Keypair::new("", "")));
|
let mut config = Self::new(Some(Keypair::new("", "")));
|
||||||
|
|
||||||
@@ -525,11 +629,13 @@ impl Rosenpass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Verbosity {
|
impl Default for Verbosity {
|
||||||
|
/// Self::Quiet
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Quiet
|
Self::Quiet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Example configuration generated by the command `rosenpass gen-config <TOML-FILE>`.
|
||||||
pub static EXAMPLE_CONFIG: &str = r###"public_key = "/path/to/rp-public-key"
|
pub static EXAMPLE_CONFIG: &str = r###"public_key = "/path/to/rp-public-key"
|
||||||
secret_key = "/path/to/rp-secret-key"
|
secret_key = "/path/to/rp-secret-key"
|
||||||
listen = []
|
listen = []
|
||||||
@@ -553,7 +659,7 @@ key_out = "/path/to/rp-key-out.txt" # path to store the key
|
|||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::{borrow::Borrow, net::IpAddr};
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
fn toml_des<S: Borrow<str>>(s: S) -> Result<toml::Table, toml::de::Error> {
|
fn toml_des<S: Borrow<str>>(s: S) -> Result<toml::Table, toml::de::Error> {
|
||||||
toml::from_str(s.borrow())
|
toml::from_str(s.borrow())
|
||||||
@@ -664,37 +770,6 @@ mod test {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_simple_cli_parse() {
|
|
||||||
let args = split_str(
|
|
||||||
"public-key /my/public-key secret-key /my/secret-key verbose \
|
|
||||||
listen 0.0.0.0:9999 peer public-key /peer/public-key endpoint \
|
|
||||||
peer.test:9999 outfile /peer/rp-out",
|
|
||||||
);
|
|
||||||
|
|
||||||
let config = Rosenpass::parse_args(args).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
config.keypair,
|
|
||||||
Some(Keypair::new("/my/public-key", "/my/secret-key"))
|
|
||||||
);
|
|
||||||
assert_eq!(config.verbosity, Verbosity::Verbose);
|
|
||||||
assert_eq!(
|
|
||||||
&config.listen,
|
|
||||||
&vec![SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9999)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
config.peers,
|
|
||||||
vec![RosenpassPeer {
|
|
||||||
public_key: PathBuf::from("/peer/public-key"),
|
|
||||||
endpoint: Some("peer.test:9999".into()),
|
|
||||||
pre_shared_key: None,
|
|
||||||
key_out: Some(PathBuf::from("/peer/rp-out")),
|
|
||||||
..Default::default()
|
|
||||||
}]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cli_parse_multiple_peers() {
|
fn test_cli_parse_multiple_peers() {
|
||||||
let args = split_str(
|
let args = split_str(
|
||||||
|
|||||||
10
rosenpass/tests/config_Rosenpass_add_if_any.rs
Normal file
10
rosenpass/tests/config_Rosenpass_add_if_any.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use rosenpass::config::Rosenpass;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn config_Rosenpass_add_if_any_example() {
|
||||||
|
let mut v = Rosenpass::empty();
|
||||||
|
v.add_if_any(4000);
|
||||||
|
|
||||||
|
assert!(v.listen.iter().any(|a| format!("{a:?}") == "0.0.0.0:4000"));
|
||||||
|
assert!(v.listen.iter().any(|a| format!("{a:?}") == "[::]:4000"));
|
||||||
|
}
|
||||||
18
rosenpass/tests/config_Rosenpass_new.rs
Normal file
18
rosenpass/tests/config_Rosenpass_new.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use rosenpass::config::{Keypair, Rosenpass};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_config_rosenpass_new() {
|
||||||
|
let (sk, pk) = ("./example.sk", "./example.pk");
|
||||||
|
|
||||||
|
assert_eq!(Rosenpass::empty(), Rosenpass::new(None));
|
||||||
|
assert_eq!(Rosenpass::empty(), Rosenpass::default());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rosenpass::from_sk_pk(sk, pk),
|
||||||
|
Rosenpass::new(Some(Keypair::new(pk, sk)))
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut v = Rosenpass::empty();
|
||||||
|
v.keypair = Some(Keypair::new(pk, sk));
|
||||||
|
assert_eq!(Rosenpass::from_sk_pk(sk, pk), v);
|
||||||
|
}
|
||||||
36
rosenpass/tests/config_Rosenpass_parse_args_simple.rs
Normal file
36
rosenpass/tests/config_Rosenpass_parse_args_simple.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use std::{
|
||||||
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use rosenpass::config::{Keypair, Rosenpass, RosenpassPeer, Verbosity};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_simple() {
|
||||||
|
let argv = "public-key /my/public-key secret-key /my/secret-key verbose \
|
||||||
|
listen 0.0.0.0:9999 peer public-key /peer/public-key endpoint \
|
||||||
|
peer.test:9999 outfile /peer/rp-out";
|
||||||
|
let argv = argv.split(' ').map(|s| s.to_string()).collect();
|
||||||
|
|
||||||
|
let config = Rosenpass::parse_args(argv).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
config.keypair,
|
||||||
|
Some(Keypair::new("/my/public-key", "/my/secret-key"))
|
||||||
|
);
|
||||||
|
assert_eq!(config.verbosity, Verbosity::Verbose);
|
||||||
|
assert_eq!(
|
||||||
|
&config.listen,
|
||||||
|
&vec![SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9999)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
config.peers,
|
||||||
|
vec![RosenpassPeer {
|
||||||
|
public_key: PathBuf::from("/peer/public-key"),
|
||||||
|
endpoint: Some("peer.test:9999".into()),
|
||||||
|
pre_shared_key: None,
|
||||||
|
key_out: Some(PathBuf::from("/peer/rp-out")),
|
||||||
|
..Default::default()
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}
|
||||||
42
rosenpass/tests/config_Rosenpass_store.rs
Normal file
42
rosenpass/tests/config_Rosenpass_store.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use rosenpass::config::{Rosenpass, Verbosity};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_config_rosenpass_store() -> anyhow::Result<()> {
|
||||||
|
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||||
|
|
||||||
|
let tmpdir = tempfile::tempdir()?;
|
||||||
|
|
||||||
|
let sk = tmpdir.path().join("example.sk");
|
||||||
|
let pk = tmpdir.path().join("example.pk");
|
||||||
|
let cfg = tmpdir.path().join("config.toml");
|
||||||
|
|
||||||
|
let mut c = Rosenpass::from_sk_pk(&sk, &pk);
|
||||||
|
|
||||||
|
// Can not commit config, path not known
|
||||||
|
assert!(c.commit().is_err());
|
||||||
|
|
||||||
|
// We can store it to an explicit path though
|
||||||
|
c.store(&cfg)?;
|
||||||
|
|
||||||
|
// Storing does not set commitment path
|
||||||
|
assert!(c.commit().is_err());
|
||||||
|
|
||||||
|
// We can reload the config now and the configurations
|
||||||
|
// are equal if we adjust the commitment path
|
||||||
|
let mut c2 = Rosenpass::load(&cfg)?;
|
||||||
|
c.config_file_path = PathBuf::from(&cfg);
|
||||||
|
assert_eq!(c, c2);
|
||||||
|
|
||||||
|
// And this loaded config can now be committed
|
||||||
|
c2.verbosity = Verbosity::Verbose;
|
||||||
|
c2.commit()?;
|
||||||
|
|
||||||
|
// And the changes actually made it to disk
|
||||||
|
let c3 = Rosenpass::load(cfg)?;
|
||||||
|
assert_eq!(c2, c3);
|
||||||
|
assert_ne!(c, c3);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
37
rosenpass/tests/config_Rosenpass_validate.rs
Normal file
37
rosenpass/tests/config_Rosenpass_validate.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use rosenpass::{cli::generate_and_save_keypair, config::Rosenpass};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_config_rosenpass_validate() -> anyhow::Result<()> {
|
||||||
|
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||||
|
|
||||||
|
let tmpdir = tempfile::tempdir()?;
|
||||||
|
|
||||||
|
// Empty validates OK
|
||||||
|
assert!(Rosenpass::empty().validate().is_ok());
|
||||||
|
|
||||||
|
// Missing secret key does not pass usefulness
|
||||||
|
assert!(Rosenpass::empty().check_usefullness().is_err());
|
||||||
|
|
||||||
|
let sk = tmpdir.path().join("example.sk");
|
||||||
|
let pk = tmpdir.path().join("example.pk");
|
||||||
|
let cfg = Rosenpass::from_sk_pk(&sk, &pk);
|
||||||
|
|
||||||
|
// Missing secret key does not validate
|
||||||
|
assert!(cfg.validate().is_err());
|
||||||
|
|
||||||
|
// But passes usefulness (the configuration is useful but invalid)
|
||||||
|
assert!(cfg.check_usefullness().is_ok());
|
||||||
|
|
||||||
|
// Providing empty key files does not help
|
||||||
|
fs::write(&sk, b"")?;
|
||||||
|
fs::write(&pk, b"")?;
|
||||||
|
assert!(cfg.validate().is_err());
|
||||||
|
|
||||||
|
// But after providing proper key files, the configuration validates
|
||||||
|
generate_and_save_keypair(sk, pk)?;
|
||||||
|
assert!(cfg.validate().is_ok());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user