logicaffeine_system/csrf.rs
1//! The page half of CSRF: a page document carries its visitor's token in its head, where the
2//! browser host reads it and sends it back as `x-csrf-token` on the page's state-changing requests
3//! to its own server. One definition for every tier that composes or reads a page — the dev
4//! server, a compiled server, the in-process host and the browser runtime's shared name.
5
6/// The `<meta name>` a page document carries its visitor's CSRF token under.
7pub const CSRF_META_NAME: &str = "csrf-token";
8
9/// `document` carrying `token` in its head as `<meta name="csrf-token">`. The meta opens the head,
10/// so a page's own `Head:` merges over it by identity like every other head element. A document
11/// with no `<head>` is returned as it is.
12pub fn with_csrf_meta(document: &str, token: &str) -> String {
13 let Some(open) = document
14 .to_ascii_lowercase()
15 .find("<head>")
16 .map(|at| at + "<head>".len())
17 else {
18 return document.to_string();
19 };
20 let escaped = token
21 .replace('&', "&")
22 .replace('<', "<")
23 .replace('>', ">")
24 .replace('"', """);
25 let tag = format!("\n<meta name=\"{CSRF_META_NAME}\" content=\"{escaped}\">");
26 format!("{}{tag}{}", &document[..open], &document[open..])
27}