//! Publish pages and share links over real HTTP: what is served, what stays hidden, //! who may publish, and how the anonymous routes are bounded. mod common; use common::Server; use notescraft_sync_server::publish; use serde_json::{Value, json}; /// The header value of a response, or an empty string. fn header(headers: &[(String, String)], name: &str) -> String { headers.iter().find(|(key, _)| key == name).map(|(_, value)| value.clone()).unwrap_or_default() } /// The body of a response as text. fn text(body: &[u8]) -> String { String::from_utf8_lossy(body).into_owned() } /// Writes one note and asserts it landed. fn note(server: &Server, vault: &str, token: &str, path: &str, body: &str) { let (status, _) = server.put(vault, token, path, body, 0); assert_eq!(status, 201, "put {path}"); } /// Publishes one note and returns the slug and the public path. fn publish_note(server: &Server, vault: &str, token: &str, target: &str) -> (String, String) { let (status, reply) = server.json("POST", &format!("/v1/vaults/{vault}/publications"), Some(token), &[], Some(&json!({"target": target, "kind": "note"}))); assert_eq!(status, 200, "{reply}"); let slug = reply["slug"].as_str().expect("slug").to_owned(); let url = reply["url_path"].as_str().expect("url").to_owned(); (slug, url) } /// The member ids of a vault, by role. fn members_by_role(server: &Server, vault: &str, token: &str) -> Vec<(String, String)> { let (_, members) = server.json("GET", &format!("/v1/vaults/{vault}/members"), Some(token), &[], None); members .as_array() .expect("members") .iter() .map(|row| (row["role"].as_str().expect("role").to_owned(), row["user_id"].as_str().expect("user id").to_owned())) .collect() } #[test] fn a_published_note_is_a_safe_static_page() { let server = Server::start_temp("publish-note"); let (vault, token, _) = server.owned_vault("note"); note(&server, &vault, &token, "hello.md", "# Hello\n\n\n\n\n\n[x](javascript:alert(1))\n"); let (slug, url) = publish_note(&server, &vault, &token, "hello.md"); assert_eq!(url, format!("/p/{slug}/hello")); let (status, headers, body) = server.send_full("GET", &url, None, &[], None); assert_eq!(status, 200); let page = text(&body); assert!(page.contains("Hello"), "{page}"); assert!(!page.contains("