Files
wireguard-admin/src/app/reissue.rs
T

98 lines
4.2 KiB
Rust

//! Freshly authenticated publication of a saved client's configuration.
use super::{Application, ReissueDelivery, ReissueError, ReissueFailureKind, ReissueStage};
use crate::delivery::files::{self, PreparedDestination};
use crate::delivery::qr;
use crate::delivery::{self, DeliverySettings};
use crate::domain::PublicKey;
use crate::vault::VaultBundle;
use crate::wireguard::ConfigDocument;
impl Application {
/// Reissue a saved client's configuration after freshly unlocking its
/// installed vault record with this action's password. This operation reads
/// only installed saved bytes, never uses a draft or retained source file,
/// and publishes the required file before attempting optional QR encoding.
pub fn reissue_client_file(
&self,
identity: PublicKey,
password: &str,
destination: PreparedDestination,
include_qr: bool,
) -> Result<ReissueDelivery, ReissueError> {
let installed = self.store.read_saved().map_err(|_| ReissueError {
stage: ReissueStage::SavedState,
kind: ReissueFailureKind::SavedStateUnavailable,
})?;
let document =
ConfigDocument::parse(&installed.server_config).map_err(|_| ReissueError {
stage: ReissueStage::SavedState,
kind: ReissueFailureKind::SavedStateUnavailable,
})?;
let encoded_vault = installed.vault.as_deref().ok_or(ReissueError {
stage: ReissueStage::Authorization,
kind: ReissueFailureKind::VaultUnavailable,
})?;
let vault_text = std::str::from_utf8(encoded_vault).map_err(|_| ReissueError {
stage: ReissueStage::Authorization,
kind: ReissueFailureKind::VaultUnavailable,
})?;
let vault = VaultBundle::from_toml(vault_text).map_err(|_| ReissueError {
stage: ReissueStage::Authorization,
kind: ReissueFailureKind::VaultUnavailable,
})?;
// Retrieval performs the password unlock and authenticated conflict
// check on every invocation. The short-lived owner is dropped when
// this method returns and is never kept in Application state.
let record = vault
.retrieve_client_record(identity, password)
.map_err(|_| ReissueError {
stage: ReissueStage::Authorization,
kind: ReissueFailureKind::PasswordOrRecordRejected,
})?;
let resolved = self
.store
.resolved_settings_for(&installed)
.map_err(|_| ReissueError {
stage: ReissueStage::SavedState,
kind: ReissueFailureKind::SavedStateUnavailable,
})?;
let delivery_settings = DeliverySettings {
server_endpoint: &resolved.server_endpoint,
dns_addresses: &resolved.dns_addresses,
};
let payload = if record.is_new_template() {
delivery::render_new_client(
identity,
record.private_key().ok_or(ReissueError {
stage: ReissueStage::Authorization,
kind: ReissueFailureKind::PasswordOrRecordRejected,
})?,
&document,
&delivery_settings,
)
} else {
delivery::render_imported_client(identity, &record, &document, &delivery_settings)
}
.map_err(|_| ReissueError {
stage: ReissueStage::Rendering,
kind: ReissueFailureKind::ConfigurationRejected,
})?;
files::publish(destination, &payload).map_err(|error| ReissueError {
stage: ReissueStage::FilePublication,
kind: ReissueFailureKind::FileOutput(error),
})?;
// A historical timestamp is deliberately insufficient: after reopen,
// the runtime observation is unknown. Warn unless this live session
// has verified the exact saved peer snapshot currently on disk.
let activation_warning = !self.saved_generation_is_verified_applied(&installed, &document);
let qr = include_qr.then(|| qr::encode_payload(&payload));
Ok(ReissueDelivery {
activation_warning,
qr,
})
}
}