//! 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("