git.delta.rocks / jrsonnet / refs/commits / d9405376effd

difftreelog

source

cmds/fleet/src/fleetdata.rs2.8 KiBsourcehistory
1use std::{2	collections::BTreeMap,3	io::{self, Cursor},4};56use age::Recipient;7use chrono::{DateTime, Utc};8use fleet_shared::SecretData;9use itertools::Itertools;10use serde::{de::Error, Deserialize, Serialize};1112#[derive(Serialize, Deserialize, Default)]13#[serde(rename_all = "camelCase")]14pub struct HostData {15	#[serde(default)]16	#[serde(skip_serializing_if = "String::is_empty")]17	pub encryption_key: String,18}1920const VERSION: &str = "0.1.0";21pub struct FleetDataVersion;22impl Serialize for FleetDataVersion {23	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>24	where25		S: serde::Serializer,26	{27		VERSION.serialize(serializer)28	}29}30impl<'de> Deserialize<'de> for FleetDataVersion {31	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>32	where33		D: serde::Deserializer<'de>,34	{35		let version = String::deserialize(deserializer)?;36		if version != VERSION {37			return Err(D::Error::custom(format!(38				"fleet.nix data version mismatch, expected {VERSION}, got {version}.\nFollow the docs for migration instruction"39			)));40		}41		Ok(Self)42	}43}4445#[derive(Serialize, Deserialize)]46#[serde(rename_all = "camelCase")]47pub struct FleetData {48	pub version: FleetDataVersion,4950	#[serde(default)]51	pub hosts: BTreeMap<String, HostData>,52	#[serde(default)]53	#[serde(skip_serializing_if = "BTreeMap::is_empty")]54	pub shared_secrets: BTreeMap<String, FleetSharedSecret>,55	#[serde(default)]56	#[serde(skip_serializing_if = "BTreeMap::is_empty")]57	pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,58}5960#[derive(Serialize, Deserialize, Clone)]61#[serde(rename_all = "camelCase")]62#[must_use]63pub struct FleetSharedSecret {64	pub owners: Vec<String>,65	#[serde(flatten)]66	pub secret: FleetSecret,67}6869/// Returns None if recipients.is_empty()70pub fn encrypt_secret_data(71	recipients: impl IntoIterator<Item = impl Recipient + Send + 'static>,72	data: Vec<u8>,73) -> Option<SecretData> {74	let mut encrypted = vec![];75	let recipients = recipients76		.into_iter()77		.map(|v| Box::new(v) as Box<dyn Recipient + Send>)78		.collect_vec();79	let mut encryptor = age::Encryptor::with_recipients(recipients)?80		.wrap_output(&mut encrypted)81		.expect("in memory write");82	io::copy(&mut Cursor::new(data), &mut encryptor).expect("in memory copy");83	encryptor.finish().expect("in memory flush");84	Some(SecretData {85		data: encrypted,86		encrypted: true,87	})88}8990#[derive(Serialize, Deserialize, Clone)]91pub struct FleetSecretPart {92	pub raw: SecretData,93}9495#[derive(Serialize, Deserialize, Clone)]96#[serde(rename_all = "camelCase")]97#[must_use]98pub struct FleetSecret {99	#[serde(default = "Utc::now")]100	pub created_at: DateTime<Utc>,101	#[serde(default)]102	#[serde(skip_serializing_if = "Option::is_none", alias = "expire_at")]103	pub expires_at: Option<DateTime<Utc>>,104105	#[serde(flatten)]106	pub parts: BTreeMap<String, FleetSecretPart>,107}