git.delta.rocks / jrsonnet / refs/commits / 20a41a30344f

difftreelog

source

crates/fleet-base/src/fleetdata.rs4.0 KiBsourcehistory
1use std::{2	collections::{BTreeMap, BTreeSet},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;1516use crate::secret::{Expectations, RegenerationReason, secret_needs_regeneration};1718#[derive(Serialize, Deserialize, Default)]19#[serde(rename_all = "camelCase")]20pub struct HostData {21	#[serde(default)]22	#[serde(skip_serializing_if = "String::is_empty")]23	pub encryption_key: String,24}2526const VERSION: &str = "0.1.0";27pub struct FleetDataVersion;28impl Serialize for FleetDataVersion {29	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>30	where31		S: serde::Serializer,32	{33		VERSION.serialize(serializer)34	}35}36impl<'de> Deserialize<'de> for FleetDataVersion {37	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>38	where39		D: serde::Deserializer<'de>,40	{41		let version = String::deserialize(deserializer)?;42		if version != VERSION {43			return Err(D::Error::custom(format!(44				"fleet.nix data version mismatch, expected {VERSION}, got {version}.\nFollow the docs for migration instruction"45			)));46		}47		Ok(Self)48	}49}5051fn generate_gc_prefix() -> String {52	let id = Alphanumeric.sample_string(&mut rng(), 8);53	format!("fleet-gc-{id}")54}5556#[derive(Serialize, Deserialize)]57#[serde(rename_all = "camelCase")]58pub struct ManagerKey {59	pub name: String,60	pub key: String,61}6263#[derive(Serialize, Deserialize)]64#[serde(rename_all = "camelCase")]65pub struct FleetData {66	pub version: FleetDataVersion,67	#[serde(default = "generate_gc_prefix")]68	pub gc_root_prefix: String,6970	#[serde(default)]71	pub manager_keys: Vec<ManagerKey>,7273	#[serde(default)]74	pub hosts: BTreeMap<String, HostData>,75	#[serde(default)]76	#[serde(skip_serializing_if = "BTreeMap::is_empty")]77	pub shared_secrets: BTreeMap<String, FleetSharedSecret>,78	#[serde(default)]79	#[serde(skip_serializing_if = "BTreeMap::is_empty")]80	pub host_secrets: BTreeMap<String, BTreeMap<String, FleetHostSecret>>,8182	// extra_name => anything83	#[serde(default)]84	#[serde(skip_serializing_if = "BTreeMap::is_empty")]85	pub extra: BTreeMap<String, Value>,86}8788/// Returns None if recipients.is_empty()89pub fn encrypt_secret_data<'r>(90	recipients: impl IntoIterator<Item = &'r Box<dyn Recipient>>,91	data: Vec<u8>,92) -> Option<SecretData> {93	let mut encrypted = vec![];94	let mut encryptor = age::Encryptor::with_recipients(recipients.into_iter().map(|v| &**v))95		.ok()?96		.wrap_output(&mut encrypted)97		.expect("in memory write");98	io::copy(&mut Cursor::new(data), &mut encryptor).expect("in memory copy");99	encryptor.finish().expect("in memory flush");100	Some(SecretData {101		data: encrypted,102		encrypted: true,103	})104}105106#[derive(Serialize, Deserialize, Clone)]107pub struct FleetSecretPart {108	pub raw: SecretData,109}110111#[derive(Serialize, Deserialize, Clone)]112#[serde(rename_all = "camelCase")]113#[must_use]114pub struct FleetSecretData {115	#[serde(default = "Utc::now")]116	pub created_at: DateTime<Utc>,117	#[serde(default)]118	#[serde(skip_serializing_if = "Option::is_none", alias = "expire_at")]119	pub expires_at: Option<DateTime<Utc>>,120121	#[serde(flatten)]122	pub parts: BTreeMap<String, FleetSecretPart>,123124	#[serde(default)]125	#[serde(skip_serializing_if = "Value::is_null")]126	pub generation_data: Value,127}128129#[derive(Serialize, Deserialize, Clone)]130#[serde(rename_all = "camelCase")]131#[must_use]132pub struct FleetHostSecret {133	#[serde(default)]134	#[serde(skip_serializing_if = "Option::is_none")]135	pub managed: Option<bool>,136	#[serde(flatten)]137	pub secret: FleetSecretData,138}139impl FleetHostSecret {140	pub fn needs_regeneration(&self, expectations: &Expectations) -> Option<RegenerationReason> {141		secret_needs_regeneration(&self.secret, &expectations.owners, expectations)142	}143}144145#[derive(Serialize, Deserialize, Clone)]146#[serde(rename_all = "camelCase")]147#[must_use]148pub struct FleetSharedSecret {149	#[serde(default)]150	#[serde(skip_serializing_if = "Option::is_none")]151	pub managed: Option<bool>,152	pub owners: BTreeSet<String>,153	#[serde(flatten)]154	pub secret: FleetSecretData,155}