git.delta.rocks / jrsonnet / refs/commits / 064468b85673

difftreelog

source

crates/fleet-base/src/fleetdata.rs2.9 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};11use serde_json::Value;1213#[derive(Serialize, Deserialize, Default)]14#[serde(rename_all = "camelCase")]15pub struct HostData {16	#[serde(default)]17	#[serde(skip_serializing_if = "String::is_empty")]18	pub encryption_key: String,19}2021const VERSION: &str = "0.1.0";22pub struct FleetDataVersion;23impl Serialize for FleetDataVersion {24	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>25	where26		S: serde::Serializer,27	{28		VERSION.serialize(serializer)29	}30}31impl<'de> Deserialize<'de> for FleetDataVersion {32	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>33	where34		D: serde::Deserializer<'de>,35	{36		let version = String::deserialize(deserializer)?;37		if version != VERSION {38			return Err(D::Error::custom(format!(39				"fleet.nix data version mismatch, expected {VERSION}, got {version}.\nFollow the docs for migration instruction"40			)));41		}42		Ok(Self)43	}44}4546#[derive(Serialize, Deserialize)]47#[serde(rename_all = "camelCase")]48pub struct FleetData {49	pub version: FleetDataVersion,5051	#[serde(default)]52	pub hosts: BTreeMap<String, HostData>,53	#[serde(default)]54	#[serde(skip_serializing_if = "BTreeMap::is_empty")]55	pub shared_secrets: BTreeMap<String, FleetSharedSecret>,56	#[serde(default)]57	#[serde(skip_serializing_if = "BTreeMap::is_empty")]58	pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,5960	// extra_name => anything61	#[serde(default)]62	#[serde(skip_serializing_if = "BTreeMap::is_empty")]63	pub extra: BTreeMap<String, Value>,64}6566#[derive(Serialize, Deserialize, Clone)]67#[serde(rename_all = "camelCase")]68#[must_use]69pub struct FleetSharedSecret {70	pub owners: Vec<String>,71	#[serde(flatten)]72	pub secret: FleetSecret,73}7475/// Returns None if recipients.is_empty()76pub fn encrypt_secret_data(77	recipients: impl IntoIterator<Item = impl Recipient + Send + 'static>,78	data: Vec<u8>,79) -> Option<SecretData> {80	let mut encrypted = vec![];81	let recipients = recipients82		.into_iter()83		.map(|v| Box::new(v) as Box<dyn Recipient + Send>)84		.collect_vec();85	let mut encryptor = age::Encryptor::with_recipients(recipients)?86		.wrap_output(&mut encrypted)87		.expect("in memory write");88	io::copy(&mut Cursor::new(data), &mut encryptor).expect("in memory copy");89	encryptor.finish().expect("in memory flush");90	Some(SecretData {91		data: encrypted,92		encrypted: true,93	})94}9596#[derive(Serialize, Deserialize, Clone)]97pub struct FleetSecretPart {98	pub raw: SecretData,99}100101#[derive(Serialize, Deserialize, Clone)]102#[serde(rename_all = "camelCase")]103#[must_use]104pub struct FleetSecret {105	#[serde(default = "Utc::now")]106	pub created_at: DateTime<Utc>,107	#[serde(default)]108	#[serde(skip_serializing_if = "Option::is_none", alias = "expire_at")]109	pub expires_at: Option<DateTime<Utc>>,110111	#[serde(flatten)]112	pub parts: BTreeMap<String, FleetSecretPart>,113}