use chrono::{TimeZone, Utc}; use waybetter_host::hotfix::{accept, minisign_text, script, validate, verify, Outcome}; // Throwaway test key pair (not a production hotfix key); fixture signed with `tauri signer sign`. const PUBKEY: &str = include_str!("fixtures/hotfix-test.key.pub"); const BODY: &[u8] = include_bytes!("fixtures/hotfix-test.json"); const SIG: &str = include_str!("fixtures/hotfix-test.json.sig"); fn now() -> chrono::DateTime { Utc.with_ymd_and_hms(2026, 9, 27, 12, 0, 0).unwrap() } #[test] fn accepts_a_signed_hotfix() { let Outcome::Accepted(hotfix) = accept(PUBKEY, BODY, SIG, now(), "0.2.0", None).unwrap() else { panic!("expected accepted"); }; assert_eq!(hotfix.version, 7); assert_eq!(hotfix.flags["hideGrok"], serde_json::json!(true)); assert!(minisign_text(PUBKEY).unwrap().contains("minisign public key")); } #[test] fn rejects_tampered_body_and_garbage() { let tampered = String::from_utf8(BODY.to_vec()).unwrap().replace("\"version\":7", "\"version\":8"); assert!(verify(PUBKEY, tampered.as_bytes(), SIG).is_err()); assert!(verify(PUBKEY, BODY, "garbage").is_err()); assert!(verify("garbage", BODY, SIG).is_err()); } #[test] fn monotonic_versions() { assert_eq!(accept(PUBKEY, BODY, SIG, now(), "0.2.0", Some(7)).unwrap(), Outcome::Unchanged); assert!(accept(PUBKEY, BODY, SIG, now(), "0.2.0", Some(8)).is_err()); assert!(matches!(accept(PUBKEY, BODY, SIG, now(), "0.2.0", Some(6)).unwrap(), Outcome::Accepted(_))); } #[test] fn expiry_and_min_native() { let late = Utc.with_ymd_and_hms(2099, 1, 1, 0, 0, 1).unwrap(); assert!(accept(PUBKEY, BODY, SIG, late, "0.2.0", None).is_err()); assert!(accept(PUBKEY, BODY, SIG, now(), "0.0.9", None).is_err()); } #[test] fn schema_rejects_code_like_or_unknown_content() { let base = |extra: &str| format!(r#"{{"version":1,"expires":"2099-01-01T00:00:00Z","minNative":"0.1.0"{extra}}}"#); assert!(validate(base("").as_bytes(), now(), "0.2.0").is_ok()); assert!(validate(base(r#","script":"alert(1)""#).as_bytes(), now(), "0.2.0").is_err()); assert!(validate(base(r#","flags":{"x":{"nested":1}}"#).as_bytes(), now(), "0.2.0").is_err()); assert!(validate(base(r#","selectors":{"bad key!":"div"}"#).as_bytes(), now(), "0.2.0").is_err()); assert!(validate(base(r#","selectors":{"k":""}"#).as_bytes(), now(), "0.2.0").is_err()); } #[test] fn script_delivers_data_only_under_the_given_names() { let Outcome::Accepted(hotfix) = accept(PUBKEY, BODY, SIG, now(), "0.2.0", None).unwrap() else { panic!() }; let script = script(&hotfix, "__demoHotfix", "demo-hotfix"); assert!(script.starts_with("(()=>{const h=JSON.parse(\"")); assert!(script.contains("window.__demoHotfix=h") && script.contains("new CustomEvent('demo-hotfix')")); // The selector's quotes are escaped inside a JSON string literal, never raw JS. assert!(!script.contains("[data-testid=\"tweetTextarea_0\"]")); }