git.delta.rocks / jrsonnet / refs/commits / 8fa5c73b5fe4

difftreelog

source

crates/fleet-base/src/fleetdata.rs3.3 KiBsourcehistory
1use std::{2	collections::BTreeMap,3	io::{self, Cursor},4};56use age::Recipient;7use chrono::{DateTime, Utc};8use fleet_shared::SecretData;9use rand::{10	distr::{Alphanumeric, SampleString as _},11	rng,12};13use serde::{Deserialize, Serialize, de::Error};14use serde_json::Value;1516#[derive(Serialize, Deserialize, Default)]17#[serde(rename_all = "camelCase")]18pub struct HostData {19	#[serde(default)]20	#[serde(skip_serializing_if = "String::is_empty")]21	pub encryption_key: String,22}2324const VERSION: &str = "0.1.0";25pub struct FleetDataVersion;26impl Serialize for FleetDataVersion {27	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>28	where29		S: serde::Serializer,30	{31		VERSION.serialize(serializer)32	}33}34impl<'de> Deserialize<'de> for FleetDataVersion {35	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>36	where37		D: serde::Deserializer<'de>,38	{39		let version = String::deserialize(deserializer)?;40		if version != VERSION {41			return Err(D::Error::custom(format!(42				"fleet.nix data version mismatch, expected {VERSION}, got {version}.\nFollow the docs for migration instruction"43			)));44		}45		Ok(Self)46	}47}4849fn generate_gc_prefix() -> String {50	let id = Alphanumeric.sample_string(&mut rng(), 8);51	format!("fleet-gc-{id}")52}5354#[derive(Serialize, Deserialize)]55#[serde(rename_all = "camelCase")]56pub struct ManagerKey {57	pub name: String,58	pub key: String,59}6061#[derive(Serialize, Deserialize)]62#[serde(rename_all = "camelCase")]63pub struct FleetData {64	pub version: FleetDataVersion,65	#[serde(default = "generate_gc_prefix")]66	pub gc_root_prefix: String,6768	#[serde(default)]69	pub manager_keys: Vec<ManagerKey>,7071	#[serde(default)]72	pub hosts: BTreeMap<String, HostData>,73	#[serde(default)]74	#[serde(skip_serializing_if = "BTreeMap::is_empty")]75	pub shared_secrets: BTreeMap<String, FleetSharedSecret>,76	#[serde(default)]77	#[serde(skip_serializing_if = "BTreeMap::is_empty")]78	pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,7980	// extra_name => anything81	#[serde(default)]82	#[serde(skip_serializing_if = "BTreeMap::is_empty")]83	pub extra: BTreeMap<String, Value>,84}8586#[derive(Serialize, Deserialize, Clone)]87#[serde(rename_all = "camelCase")]88#[must_use]89pub struct FleetSharedSecret {90	pub owners: Vec<String>,91	#[serde(flatten)]92	pub secret: FleetSecret,93}9495/// Returns None if recipients.is_empty()96pub fn encrypt_secret_data<'a>(97	recipients: impl IntoIterator<Item = &'a dyn Recipient>,98	data: Vec<u8>,99) -> Option<SecretData> {100	let mut encrypted = vec![];101	let mut encryptor = age::Encryptor::with_recipients(recipients.into_iter())102		.ok()?103		.wrap_output(&mut encrypted)104		.expect("in memory write");105	io::copy(&mut Cursor::new(data), &mut encryptor).expect("in memory copy");106	encryptor.finish().expect("in memory flush");107	Some(SecretData {108		data: encrypted,109		encrypted: true,110	})111}112113#[derive(Serialize, Deserialize, Clone)]114pub struct FleetSecretPart {115	pub raw: SecretData,116}117118#[derive(Serialize, Deserialize, Clone)]119#[serde(rename_all = "camelCase")]120#[must_use]121pub struct FleetSecret {122	#[serde(default = "Utc::now")]123	pub created_at: DateTime<Utc>,124	#[serde(default)]125	#[serde(skip_serializing_if = "Option::is_none", alias = "expire_at")]126	pub expires_at: Option<DateTime<Utc>>,127128	#[serde(flatten)]129	pub parts: BTreeMap<String, FleetSecretPart>,130131	#[serde(default)]132	#[serde(skip_serializing_if = "Value::is_null")]133	pub generation_data: Value,134}