[Fix] Stability
This commit is contained in:
parent
e1dd86ec02
commit
8160f8d0cb
44 changed files with 796 additions and 1296 deletions
|
|
@ -4,8 +4,7 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
iota-state = { path = "../iota-state" }
|
||||
iota-util = { path = "../iota-util" }
|
||||
|
||||
json = "*"
|
||||
reqwest = "0.13.2"
|
||||
tokio = { version = "1.50.0", features = ["macros"] }
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ impl ConsentRecord {
|
|||
}
|
||||
|
||||
fn matches_doc(value: &Option<(String, String)>, doc: &Doc) -> bool {
|
||||
matches!(value, Some((version, hash)) if version == &doc.get_version() && hash == &doc.get_hash())
|
||||
matches!(value, Some((_, hash)) if hash == &doc.get_hash())
|
||||
}
|
||||
|
||||
pub fn load(state_dir: &Path) -> ConsentRecord {
|
||||
|
|
@ -82,8 +82,5 @@ pub fn save(state_dir: &Path, record: &ConsentRecord) -> io::Result<()> {
|
|||
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)
|
||||
iota_util::atomic_file::replace(&state_dir.join(FILE_NAME), text.as_bytes(), 3)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use json::{JsonValue, object::Object};
|
||||
|
||||
use crate::terms_getter::Type;
|
||||
use iota_util::file_util::load_file;
|
||||
use iota_util::crypto_helper::hex_hash;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[allow(unused)]
|
||||
|
|
@ -23,15 +21,24 @@ impl Doc {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_raw(doc_type: Type, content: String, timestamp: u64) -> Doc {
|
||||
Doc::new(
|
||||
timestamp.to_string(),
|
||||
hex_hash(&content),
|
||||
doc_type,
|
||||
timestamp,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn equals_some(&self, other: &Option<Self>) -> bool {
|
||||
if let Some(other) = other {
|
||||
self.get_version() == other.get_version() && self.get_hash() == other.get_hash()
|
||||
self.equals(other)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn equals(&self, other: &Self) -> bool {
|
||||
self.get_version() == other.get_version() && self.get_hash() == other.get_hash()
|
||||
self.get_hash() == other.get_hash()
|
||||
}
|
||||
|
||||
pub fn get_version(&self) -> String {
|
||||
|
|
@ -41,34 +48,36 @@ impl Doc {
|
|||
self.hash.clone()
|
||||
}
|
||||
pub fn get_time(&self) -> u64 {
|
||||
self.timestamp.clone()
|
||||
self.timestamp
|
||||
}
|
||||
pub fn get_content(&self) -> String {
|
||||
load_file(
|
||||
format!("docs/{}/", self.doc_type.to_str()).as_str(),
|
||||
format!("{}.md", self.version).as_str(),
|
||||
)
|
||||
#[cfg(test)]
|
||||
fn timestamp(&self) -> u64 {
|
||||
self.timestamp
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> JsonValue {
|
||||
let mut json = JsonValue::new_object();
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Doc;
|
||||
use crate::terms_getter::Type;
|
||||
use iota_util::crypto_helper::hex_hash;
|
||||
|
||||
let _ = json.insert("version", self.version.clone());
|
||||
let _ = json.insert("hash", self.hash.clone());
|
||||
let _ = json.insert("unix", self.timestamp.clone());
|
||||
#[test]
|
||||
fn raw_documents_use_a_local_timestamp_and_content_hash() {
|
||||
let content = "# EULA\n".to_owned();
|
||||
let document = Doc::from_raw(Type::EULA, content.clone(), 123);
|
||||
|
||||
json
|
||||
assert_eq!(document.doc_type, Type::EULA);
|
||||
assert_eq!(document.get_version(), "123");
|
||||
assert_eq!(document.timestamp(), 123);
|
||||
assert_eq!(document.get_hash(), hex_hash(&content));
|
||||
}
|
||||
pub fn from_json(doc_type: Type, json: Object) -> Option<Self> {
|
||||
let hash = json.get("hash")?.as_str()?.to_string();
|
||||
let version = json.get("version")?.as_str()?.to_string();
|
||||
let timestamp = json.get("unix")?.as_u64()?;
|
||||
|
||||
Some(Doc {
|
||||
version,
|
||||
hash,
|
||||
doc_type,
|
||||
timestamp,
|
||||
})
|
||||
#[test]
|
||||
fn matching_documents_ignore_the_fetch_timestamp() {
|
||||
let earlier = Doc::from_raw(Type::EULA, "# EULA\n".to_owned(), 123);
|
||||
let later = Doc::from_raw(Type::EULA, "# EULA\n".to_owned(), 456);
|
||||
|
||||
assert!(earlier.equals(&later));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ pub mod terms_getter;
|
|||
pub use terms_getter::Type as TermsType;
|
||||
pub use terms_getter::get_current_docs;
|
||||
pub use terms_getter::get_link;
|
||||
pub use terms_getter::get_newest_docs;
|
||||
// pub use terms_getter::get_newest_docs;
|
||||
pub use terms_getter::get_newest_link;
|
||||
pub use terms_getter::get_terms;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use json::JsonValue::Object;
|
||||
|
||||
use crate::doc::Doc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Type {
|
||||
|
|
@ -13,8 +12,8 @@ impl Type {
|
|||
pub fn to_str(&self) -> &str {
|
||||
match self {
|
||||
Self::EULA => "eula",
|
||||
Self::TOS => "tos",
|
||||
Self::PP => "privacy",
|
||||
Self::TOS => "terms-of-service",
|
||||
Self::PP => "privacy-policy",
|
||||
}
|
||||
}
|
||||
pub fn to_string(&self) -> String {
|
||||
|
|
@ -27,79 +26,73 @@ impl Type {
|
|||
}
|
||||
|
||||
pub fn get_link(terms_type: Type) -> String {
|
||||
format!("https://legal.tensamin.net/{}/", terms_type.to_str())
|
||||
format!(
|
||||
"https://legal.methanium.net/tensamin/{}",
|
||||
terms_type.to_str()
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* The legal service exposes only its latest raw documents. Keep this helper
|
||||
* for the dormant pre-emptive-acceptance UI until it has a source of future
|
||||
* document versions again.
|
||||
*/
|
||||
pub fn get_newest_link(terms_type: Type) -> String {
|
||||
format!("https://legal.tensamin.net/{}/newest/", terms_type.to_str())
|
||||
get_link(terms_type)
|
||||
}
|
||||
|
||||
pub async fn get_current_docs() -> Option<(Doc, Doc, Doc)> {
|
||||
let body = reqwest::get("https://legal.tensamin.net/api/current/")
|
||||
.await
|
||||
.ok()?
|
||||
.text()
|
||||
.await
|
||||
.ok()?;
|
||||
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).ok()?.as_secs();
|
||||
let (eula, tos, privacy) = tokio::join!(
|
||||
get_terms(Type::EULA),
|
||||
get_terms(Type::TOS),
|
||||
get_terms(Type::PP),
|
||||
);
|
||||
|
||||
let json = json::parse(&body).ok()?;
|
||||
|
||||
if let Object(eula) = &json["eula"] {
|
||||
if let Object(tos) = &json["tos"] {
|
||||
if let Object(pp) = &json["pp"] {
|
||||
Some((
|
||||
Doc::from_json(Type::EULA, eula.clone())?,
|
||||
Doc::from_json(Type::TOS, tos.clone())?,
|
||||
Doc::from_json(Type::PP, pp.clone())?,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some((
|
||||
Doc::from_raw(Type::EULA, eula?, timestamp),
|
||||
Doc::from_raw(Type::TOS, tos?, timestamp),
|
||||
Doc::from_raw(Type::PP, privacy?, timestamp),
|
||||
))
|
||||
}
|
||||
|
||||
/*
|
||||
* Future documents are unavailable from the raw endpoint. Restore this API
|
||||
* with the pre-emptive-acceptance flow when the service provides them again.
|
||||
*
|
||||
pub async fn get_newest_docs() -> Option<(Doc, Doc, Doc)> {
|
||||
let body = reqwest::get("https://legal.tensamin.net/api/newest/")
|
||||
.await
|
||||
.ok()?
|
||||
.text()
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
let json = json::parse(&body).ok()?;
|
||||
|
||||
if let Object(eula) = &json["eula"] {
|
||||
if let Object(tos) = &json["tos"] {
|
||||
if let Object(pp) = &json["pp"] {
|
||||
Some((
|
||||
Doc::from_json(Type::EULA, eula.clone())?,
|
||||
Doc::from_json(Type::TOS, tos.clone())?,
|
||||
Doc::from_json(Type::PP, pp.clone())?,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
*/
|
||||
|
||||
pub async fn get_terms(terms_type: Type) -> Option<String> {
|
||||
let body = reqwest::get(format!(
|
||||
"https://legal.tensamin.net/api/text/{}/",
|
||||
reqwest::get(format!(
|
||||
"https://legal.methanium.net/tensamin/{}/raw",
|
||||
terms_type.to_str()
|
||||
))
|
||||
.await
|
||||
.ok()?
|
||||
.text()
|
||||
.await
|
||||
.ok()?;
|
||||
.ok()
|
||||
}
|
||||
|
||||
Some(body)
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Type, get_link};
|
||||
|
||||
#[test]
|
||||
fn maps_document_types_to_tensamin_raw_document_names() {
|
||||
assert_eq!(Type::EULA.to_str(), "eula");
|
||||
assert_eq!(Type::TOS.to_str(), "terms-of-service");
|
||||
assert_eq!(Type::PP.to_str(), "privacy-policy");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn links_to_the_tensamin_document_page() {
|
||||
assert_eq!(
|
||||
get_link(Type::TOS),
|
||||
"https://legal.methanium.net/tensamin/terms-of-service"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue