1use anyhow::Result;2use chrono::{DateTime, Utc};3use nixlike::format_nix;4use serde::{Deserialize, Deserializer, Serialize, Serializer};5use std::collections::BTreeMap;6use tempfile::TempDir;7use tokio::{8 fs::{self, File},9 io::AsyncWriteExt,10 process::Command,11};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}2021#[derive(Serialize, Deserialize)]22#[serde(rename_all = "camelCase")]23pub struct FleetData {24 #[serde(default)]25 pub hosts: BTreeMap<String, HostData>,26 #[serde(default)]27 #[serde(skip_serializing_if = "BTreeMap::is_empty")]28 pub shared_secrets: BTreeMap<String, FleetSharedSecret>,29 #[serde(default)]30 #[serde(skip_serializing_if = "BTreeMap::is_empty")]31 pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,32}3334#[derive(Serialize, Deserialize, Clone)]35#[serde(rename_all = "camelCase")]36#[must_use]37pub struct FleetSharedSecret {38 pub owners: Vec<String>,39 #[serde(flatten)]40 pub secret: FleetSecret,41}4243#[derive(Serialize, Deserialize, Clone)]44#[serde(rename_all = "camelCase")]45#[must_use]46pub struct FleetSecret {47 #[serde(default)]48 #[serde(skip_serializing_if = "Option::is_none")]49 pub expire_at: Option<DateTime<Utc>>,50 #[serde(skip_serializing_if = "Option::is_none")]51 pub public: Option<String>,52 #[serde(53 default,54 skip_serializing_if = "Vec::is_empty",55 serialize_with = "as_z85",56 deserialize_with = "from_z85"57 )]58 pub secret: Vec<u8>,59}6061fn as_z85<S>(key: &[u8], serializer: S) -> Result<S::Ok, S::Error>62where63 S: Serializer,64{65 serializer.serialize_str(&z85::encode(key))66}6768fn from_z85<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>69where70 D: Deserializer<'de>,71{72 use serde::de::Error;73 String::deserialize(deserializer)74 .and_then(|string| z85::decode(string).map_err(|err| Error::custom(err.to_string())))75}767778#[allow(dead_code)]79pub async fn dummy_flake() -> Result<TempDir> {80 let data_str = fs::read_to_string("fleet.nix").await?;8182 let mut cmd = Command::new("nix");83 cmd.arg("flake").arg("metadata").arg("--json");8485 let flake_dir = tempfile::tempdir()?;86 let mut flake_nix = flake_dir.path().to_path_buf();87 flake_nix.push("flake.nix");88 8990 File::create(&flake_nix)91 .await?92 .write_all(93 format_nix(&format!(94 "95 {{96 outputs = {{self, ...}}: {{97 data = {data_str};98 }};99 }}100 "101 ))102 .as_bytes(),103 )104 .await?;105106 107 108 109 dbg!(&flake_nix);110 Ok(flake_dir)111}