caching
This commit is contained in:
parent
6a535099bb
commit
009173a97d
49 changed files with 1788 additions and 389 deletions
89
iota-terms/src/consent.rs
Normal file
89
iota-terms/src/consent.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
//! Durable, deployment-scoped consent records.
|
||||
//!
|
||||
//! This deliberately contains no UI code. Both the terminal client and the
|
||||
//! daemon use the same record so a UI-local decision can never start services.
|
||||
|
||||
use crate::{Doc, TermsType as Type};
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
const FILE_NAME: &str = "terms-consent-v1";
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ConsentRecord {
|
||||
pub eula: Option<(String, String)>,
|
||||
pub tos: Option<(String, String)>,
|
||||
pub privacy: Option<(String, String)>,
|
||||
}
|
||||
|
||||
impl ConsentRecord {
|
||||
pub fn has_all_required(&self) -> bool {
|
||||
self.eula.is_some() && self.tos.is_some() && self.privacy.is_some()
|
||||
}
|
||||
|
||||
pub fn accepts(&self, eula: &Doc, tos: &Doc, privacy: &Doc) -> bool {
|
||||
matches_doc(&self.eula, eula)
|
||||
&& matches_doc(&self.tos, tos)
|
||||
&& matches_doc(&self.privacy, privacy)
|
||||
}
|
||||
|
||||
pub fn accept(&mut self, doc: &Doc) {
|
||||
let value = Some((doc.get_version(), doc.get_hash()));
|
||||
match doc.doc_type {
|
||||
Type::EULA => self.eula = value,
|
||||
Type::TOS => self.tos = value,
|
||||
Type::PP => self.privacy = value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn matches_doc(value: &Option<(String, String)>, doc: &Doc) -> bool {
|
||||
matches!(value, Some((version, hash)) if version == &doc.get_version() && hash == &doc.get_hash())
|
||||
}
|
||||
|
||||
pub fn load(state_dir: &Path) -> ConsentRecord {
|
||||
let Ok(text) = fs::read_to_string(state_dir.join(FILE_NAME)) else {
|
||||
return ConsentRecord::default();
|
||||
};
|
||||
let mut record = ConsentRecord::default();
|
||||
for line in text.lines() {
|
||||
let Some((key, value)) = line.split_once('=') else {
|
||||
continue;
|
||||
};
|
||||
let Some((version, hash)) = value.split_once(':') else {
|
||||
continue;
|
||||
};
|
||||
let value = Some((version.to_owned(), hash.to_owned()));
|
||||
match key {
|
||||
"eula" => record.eula = value,
|
||||
"tos" => record.tos = value,
|
||||
"privacy" => record.privacy = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
record
|
||||
}
|
||||
|
||||
pub fn save(state_dir: &Path, record: &ConsentRecord) -> io::Result<()> {
|
||||
fs::create_dir_all(state_dir)?;
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
let mut text = format!("# Iota terms consent record; accepted_at_unix={timestamp}\n");
|
||||
for (name, value) in [
|
||||
("eula", &record.eula),
|
||||
("tos", &record.tos),
|
||||
("privacy", &record.privacy),
|
||||
] {
|
||||
if let Some((version, hash)) = value {
|
||||
text.push_str(&format!("{name}={version}:{hash}\n"));
|
||||
}
|
||||
}
|
||||
let path = state_dir.join(FILE_NAME);
|
||||
let temporary = state_dir.join(format!(".{FILE_NAME}.{}.tmp", std::process::id()));
|
||||
fs::write(&temporary, text)?;
|
||||
fs::rename(temporary, path)
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod consent;
|
||||
pub mod terms_getter;
|
||||
|
||||
pub use terms_getter::Type as TermsType;
|
||||
|
|
|
|||
Loading…
Reference in a new issue