crates/monetize-server/src/estate_order/first_link.rs
//! **The operator sends a laid site's first sign-in link again, to a new address** (owner
//! 2026-10-22: holger-rs was ordered with a placeholder `--admin` address). A site's ready
//! mail carries its ONLY first sign-in link and goes ONCE ([`super::tell`], `run.told`) to the
//! order's address; nothing changed the address or sent it again.
//!
//! `monetize site first-link <site> --to <address>` (door `POST /site/first-link`, the
//! operator bearer alone):
//!
//! * the address is set on the run (`run.email`), and the `estate.ready` mail goes again to it
//! with the link the custody holds ([`super::first_login_link`]); the history says "first
//! sign-in link re-sent by the operator to <masked address>". The link and the invite are
//! never logged;
//! * **the site's own first-admin door is asked first** ([`super::Installer::first_door`], at
//! its public front, as the sale check asks it): the site holds the invite's hash and its
//! lifetime from its install, so the custody's invite is the ONLY one it opens. A spent door
//! (the first admin has signed in) is refused by name, `[site-first-link-spent]`. A door the
//! invite no longer opens (its lifetime is over, or the site no longer takes it) is NOT
//! refused any more (HOL-FIRST-ADMIN, test2.holger.rs 2026-10-30, where it left the first
//! admin no way in): a new invite minted here would open nothing on the site, so its MAIN is
//! asked, as after a hand-off (below);
//! * **the invite is the custody's, and only until the hand-off**: once the site took its
//! material and the custody forgot it, the ONE box holds no invite, and minting one here would
//! open nothing on the site: its MAIN mints one;
//! * **FIRST-LINK-1 (owner 2026-10-27): no `--to`** is the first admin's recorded address
//! (`run.email`). The ONE box asks the site's MAIN to mint a new link, with the same signed
//! `sign_in_again` order a sold estate's resend is ([`super::send_sign_in_again`], under the
//! site's LABEL, its rate limit), and the main mails it. **HOL-FIRST-ADMIN: `--to`** is the
//! address the main mails instead; it is the recorded one from the moment the order is queued
//! (a refused ask changes nothing). `site status` says the first-admin door ([`door_of`]):
//! open, spent, expired or handed off, with the main's newest answer, its address masked;
//! * a run that is not an operator site, a site that is not laid and ready, and a malformed
//! address are refused, and nothing changes.
use super::{lifecycle, phase, run_terms, save, FirstDoor, SaleCheckAt, StartRefusal, Transition};
use crate::state::AppState;
/// The refusal tag of a spent first-admin door.
pub const SPENT: &str = "[site-first-link-spent]";
/// The refusal tag of a malformed address.
pub const ADDRESS: &str = "[site-first-link-address]";
/// The refusal tag of a run that is not a laid, ready operator site.
pub const NOT_READY: &str = "[site-first-link-not-ready]";
/// Pure: **is `to` one plain mail address** — `local@domain.tld`, no spaces, no list, no
/// display name, at most 254 characters.
pub fn address_ok(to: &str) -> bool {
let to = to.trim();
if to.is_empty()
|| to.len() > 254
|| to.chars().any(|c| {
c.is_whitespace()
|| c.is_control()
|| matches!(
c,
',' | ';' | '<' | '>' | '"' | '(' | ')' | '[' | ']' | '\\'
)
})
{
return false;
}
let Some((local, domain)) = to.split_once('@') else {
return false;
};
if local.is_empty() || local.len() > 64 || domain.contains('@') {
return false;
}
let labels: Vec<&str> = domain.split('.').collect();
labels.len() >= 2
&& labels.iter().all(|l| {
!l.is_empty()
&& !l.starts_with('-')
&& !l.ends_with('-')
&& l.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')
})
}
/// Pure: **an address as the history and the logs show it** — its first character, `***`,
/// and its domain (`o***@example.org`).
pub fn masked(to: &str) -> String {
match to.trim().split_once('@') {
Some((local, domain)) => format!(
"{}***@{domain}",
local.chars().next().map(String::from).unwrap_or_default()
),
None => "***".into(),
}
}
/// Pure: `text` with every mail address in it masked ([`masked`]) — a main's answer names the
/// address it mailed; the operator reads it masked.
pub fn masked_in(text: &str) -> String {
let mut out = String::with_capacity(text.len());
let mut rest = text;
while !rest.is_empty() {
let ws = rest
.find(|c: char| !c.is_whitespace())
.unwrap_or(rest.len());
out.push_str(&rest[..ws]);
rest = &rest[ws..];
let end = rest.find(char::is_whitespace).unwrap_or(rest.len());
let token = &rest[..end];
rest = &rest[end..];
let from = token
.find(|c: char| c.is_ascii_alphanumeric())
.unwrap_or(token.len());
let to = token
.rfind(|c: char| c.is_ascii_alphanumeric())
.map_or(from, |i| (i + 1).max(from));
let core = &token[from..to];
if core.contains('@') && address_ok(core) {
out.push_str(&token[..from]);
out.push_str(&masked(core));
out.push_str(&token[to..]);
} else {
out.push_str(token);
}
}
out
}
/// **The first-admin door's words** as `site status` says them (FIRST-LINK-1).
pub mod door {
/// The custody's invite still opens it: the ready mail's link signs the first admin in.
pub const OPEN: &str = "open";
/// The first admin has signed in (a passkey is held).
pub const SPENT: &str = "spent";
/// The invite's lifetime is over: the site no longer takes it.
pub const EXPIRED: &str = "expired";
/// The site took its secrets and the ONE box forgot them: its main mints a new link.
pub const HANDED_OFF: &str = "handed_off";
/// The door could not be asked.
pub const UNKNOWN: &str = "unknown";
}
/// What a product's main answers a `sign_in_again` with when its account holds a passkey
/// (holger `PasskeyStore::mint_sign_in_again`, gunnar `repair`): the first link is spent.
pub const PASSKEY_HELD: &str = "already signs in with a passkey";
/// **The site's own first-admin door, asked with the custody's invite** (the run's custody
/// must hold it). The outer `Err`: the run cannot be asked at all; the inner: the door did not
/// answer.
fn ask_door(
state: &AppState,
run: &super::EstateRun,
) -> Result<Result<FirstDoor, String>, StartRefusal> {
let eo = &state.estates;
let name = &run.estate;
let terms = run_terms(state, run)
.ok_or_else(|| StartRefusal::NotSold(format!("{name}'s terms are not readable here")))?;
let host = terms.host_of(&run.company);
let custody = eo.custody.as_ref().ok_or_else(|| {
StartRefusal::NotNow(format!(
"{NOT_READY} no custody holds {name}'s first sign-in invite"
))
})?;
let secrets = custody.unseal(&run.company).map_err(|e| {
StartRefusal::NotNow(format!("{NOT_READY} {name}'s custody does not open: {e}"))
})?;
let invite = secrets
.first_login
.as_ref()
.map(|b| super::hex_of(b))
.ok_or_else(|| {
StartRefusal::NotNow(format!(
"{NOT_READY} the custody holds no first sign-in invite for {name}"
))
})?;
let console_token = super::hex_of(&secrets.break_glass);
let run_dir = eo
.run_dir(&run.company)
.ok_or_else(|| StartRefusal::NotSold("no estate-orders directory".into()))?;
let life = lifecycle::of(&terms).map_err(StartRefusal::NotSold)?;
let front_role = life.update_plan().front_role;
let laid = run.laid.clone();
let facts = super::pairing_facts(&terms);
let at = SaleCheckAt {
facts: &facts,
company: &run.company,
host: &host,
account: &run.account,
front: laid.as_ref().and_then(|l| l.machine(&front_role)),
run_dir: &run_dir,
console_token: &console_token,
first_login: &invite,
};
Ok(eo
.installer
.first_door(&at)
.map_err(|why| format!("{why} (at https://{host})")))
}
/// **`site status`'s first-admin door** of a laid operator site (FIRST-LINK-1): `(word,
/// sentence)` — the site's own door asked while the custody holds the invite; after the
/// hand-off, what its main answered the newest `sign_in_again` (the address masked). Empty for
/// anything else.
pub fn door_of(state: &AppState, run: &super::EstateRun) -> (String, String) {
if !run.site_order || run.phase != phase::CAPTURED || run.account.is_empty() {
return Default::default();
}
let name = &run.estate;
let Some(custody) = state.estates.custody.as_ref() else {
return (
door::UNKNOWN.into(),
format!("no custody holds {name}'s first sign-in invite here"),
);
};
if !custody.holds(&run.company) {
return handed_off_door(state, run);
}
let (word, words) = match ask_door(state, run) {
Ok(Ok(FirstDoor::Open)) => (door::OPEN, format!("{name}'s first-admin door is open: the ready mail's first sign-in link signs {} in, once", run.account)),
Ok(Ok(FirstDoor::Spent)) => (door::SPENT, format!("{name}'s first admin has signed in already: the first-admin door is spent")),
Ok(Ok(FirstDoor::Closed(why))) => match main_answer(state, run) {
Some((word, words)) => (if word == door::SPENT { door::SPENT } else { door::EXPIRED }, format!("{name}'s first sign-in invite no longer opens its first-admin door ({why}); {words}")),
None => (door::EXPIRED, format!("{name}'s first sign-in invite no longer opens its first-admin door ({why}); `site first-link {name}` asks its main to mint a new link")),
},
Ok(Err(why)) => (door::UNKNOWN, format!("{name}'s first-admin door could not be asked: {why}")),
Err(r) => (door::UNKNOWN, r.to_string()),
};
(word.into(), masked_in(&words))
}
/// [`door_of`] of a handed-off site: its main's newest answer to a `sign_in_again`.
fn handed_off_door(state: &AppState, run: &super::EstateRun) -> (String, String) {
let name = &run.estate;
let (word, words) = match main_answer(state, run) {
Some((w, words)) if w == door::SPENT => (door::SPENT, words),
Some((_, words)) => (door::HANDED_OFF, format!("{name} is handed off; {words}")),
None => (door::HANDED_OFF, format!("{name} is handed off: the ONE box holds no first sign-in invite; `site first-link {name}` asks its main to mint a new link and mail it to {}", masked(&run.email))),
};
(word.into(), masked_in(&words))
}
/// **The site's main's newest answer to a `sign_in_again`** (`(word, words)`; `None`: it was
/// never asked): not pulled yet, refused, minted and mailed, or spent (a passkey is held).
fn main_answer(state: &AppState, run: &super::EstateRun) -> Option<(&'static str, String)> {
use monetize_embed::fleet::kind;
let (name, fleet) = (&run.estate, run.fleet_name());
let role = run_terms(state, run)
.and_then(|t| lifecycle::of(&t).ok())
.map(|l| l.primary_role())?;
let g = state.fleet.guardian()?;
let queued = g
.store
.orders_for(fleet, &role, 0)
.into_iter()
.filter(|o| o.kind == kind::SIGN_IN_AGAIN)
.map(|o| o.seq)
.max();
let acked = g.store.box_record(fleet, &role).and_then(|b| {
b.acks
.into_iter()
.filter(|a| a.kind == kind::SIGN_IN_AGAIN)
.max_by_key(|a| a.seq)
});
Some(match (queued, acked) {
(Some(q), a) if a.as_ref().is_none_or(|a| a.seq < q) => (door::HANDED_OFF, format!("a new first sign-in link was asked; its {role} has not pulled the order yet")),
(_, Some(a)) if !a.ok && a.detail.contains(PASSKEY_HELD) => (door::SPENT, format!("{name}'s first admin signs in with a passkey already; its {role} answered the last ask: {}", a.detail)),
(_, Some(a)) if a.ok => (door::HANDED_OFF, format!("its {role} answered the last ask: {}", a.detail)),
(_, Some(a)) => (door::HANDED_OFF, format!("its {role} refused the last ask: {}", a.detail)),
_ => return None,
})
}
/// **A handed-off site's first link, minted by its main** (FIRST-LINK-1): the signed
/// `sign_in_again` order ([`super::send_sign_in_again`], its rate limit, under the site's
/// label) for the first admin's RECORDED address. The words mask it.
///
/// HOL-MAIL (holger-rs 2026-10-27): the words promise nothing — the main may refuse (a main fed
/// no relay mails nothing). They name the order queued (`asked`); what the main answered is the
/// site's status ([`answer_of`], [`door_of`]), which `site first-link` follows.
fn by_main(
state: &AppState,
name: &str,
run: &super::EstateRun,
to: &str,
why: &str,
) -> Result<FirstLinkAsked, StartRefusal> {
let to = if to.is_empty() { run.email.trim() } else { to };
if !address_ok(to) {
return Err(StartRefusal::BadName(format!("{ADDRESS} {name}'s recorded first-admin address {:?} is not one mail address: give --to; nothing was asked", masked(to))));
}
let a = super::ask_sign_in_again(state, &run.company, Some(to))?;
eprintln!("monetize-server: site {name}: the operator asked its main for a new first sign-in link for {} (to {}), order {}", run.account, masked(to), a.seq);
Ok(FirstLinkAsked {
words: format!(
"{name} {why}: its {} was asked to mint a new sign-in link for {} and mail it to {} (signed order {}, the link works once, for {}); nothing is mailed until the {} answers — `site status {name}` says its answer",
a.role,
run.account,
masked(to),
a.seq,
a.ttl,
a.role
),
asked: a.seq,
})
}
/// **What `site first-link` asked** (HOL-MAIL): the words, and the seq of the signed
/// `sign_in_again` order queued for a handed-off site's main (0: no main was asked).
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct FirstLinkAsked {
pub words: String,
pub asked: u64,
}
/// **A handed-off site's main's newest answer to a `sign_in_again`** (HOL-MAIL): `(seq, mailed)`
/// — the seq of the newest order it answered (0: none) and whether it minted and mailed the
/// link (false: it refused, its reason in [`door_of`]'s words). `(0, false)` for a site whose
/// main was never asked, and for anything that is not a laid operator site.
pub fn answer_of(state: &AppState, run: &super::EstateRun) -> (u64, bool) {
use monetize_embed::fleet::kind;
if !run.site_order || run.phase != phase::CAPTURED {
return (0, false);
}
let role = run_terms(state, run)
.and_then(|t| lifecycle::of(&t).ok())
.map(|l| l.primary_role());
let (Some(g), Some(role)) = (state.fleet.guardian(), role) else {
return (0, false);
};
g.store
.box_record(run.fleet_name(), &role)
.and_then(|b| {
b.acks
.into_iter()
.filter(|a| a.kind == kind::SIGN_IN_AGAIN)
.max_by_key(|a| a.seq)
})
.map_or((0, false), |a| {
(a.seq, a.ok && !a.detail.contains(PASSKEY_HELD))
})
}
/// **`EstateOrder.FirstLink`**: send the site `name`'s first sign-in link again, to `to`.
/// `Ok` is what the operator reads.
pub fn first_link(state: &AppState, name: &str, to: &str) -> Result<String, StartRefusal> {
first_link_asking(state, name, to).map(|a| a.words)
}
/// **`EstateOrder.FirstLink`** with the order it queued for a handed-off site's main
/// ([`FirstLinkAsked::asked`]; 0: no main was asked, the words are the whole answer).
pub fn first_link_asking(
state: &AppState,
name: &str,
to: &str,
) -> Result<FirstLinkAsked, StartRefusal> {
let said = |words: String| FirstLinkAsked { words, asked: 0 };
let name = name.trim().to_ascii_lowercase();
let to = to.trim().to_string();
// FIRST-LINK-1: no address is the first admin's recorded one.
if !to.is_empty() && !address_ok(&to) {
return Err(StartRefusal::BadName(format!(
"{ADDRESS} {:?} is not one mail address (local@domain): nothing was changed or sent",
masked(&to)
)));
}
let eo = &state.estates;
let base = eo.cfg.as_ref().ok_or_else(|| {
StartRefusal::NotSold("this monetize lays no sites ([estate_orders] is absent)".into())
})?;
let Some(run) = eo.get(&name).filter(|r| !phase::is_gone(&r.phase)) else {
return Err(StartRefusal::NotFound(format!(
"{name} is not a site this box laid: no first sign-in link to send"
)));
};
if !run.site_order {
return Err(StartRefusal::NotNow(format!("{NOT_READY} {name} is not one of the operator's sites: a sold estate's link is its buyer's (sign in again)")));
}
if run.phase != phase::CAPTURED {
return Err(StartRefusal::NotNow(format!("{NOT_READY} {name} is not laid and ready (it is {}): its ready mail carries the first sign-in link once it is", run.phase)));
}
if run.account.is_empty() {
return Err(StartRefusal::NotNow(format!(
"{NOT_READY} {name} names no first admin: there is no first sign-in link to send"
)));
}
let custody = eo.custody.as_ref().ok_or_else(|| {
StartRefusal::NotNow(format!(
"{NOT_READY} no custody holds {name}'s first sign-in invite"
))
})?;
if !custody.holds(&run.company) {
return by_main(state, &name, &run, &to, "is handed off");
}
let to_given = to.clone();
let to = if to.is_empty() {
run.email.trim().to_string()
} else {
to
};
if !address_ok(&to) {
return Err(StartRefusal::BadName(format!("{ADDRESS} {name}'s recorded first-admin address {:?} is not one mail address: give --to; nothing was changed or sent", masked(&to))));
}
let _pen = eo.pen_for_a_call(base, &run.company)?;
// Read again under the pen: the run is written by its own pen only.
let Some(mut run) = eo.get(&run.company) else {
return Err(StartRefusal::NotFound(format!("{name} is gone")));
};
let host = run_terms(state, &run)
.ok_or_else(|| StartRefusal::NotSold(format!("{name}'s terms are not readable here")))?
.host_of(&run.company);
// The site's own door, at its public front, with the invite the custody holds.
match ask_door(state, &run)?.map_err(|why| StartRefusal::Busy(format!("{name}'s first-admin door could not be asked at https://{host}: {why}; nothing was changed or sent"))) {
Ok(FirstDoor::Open) => {}
Ok(FirstDoor::Spent) => return Err(StartRefusal::NotNow(format!("{SPENT} {name}'s first admin has signed in already; use passkeys/recovery on the site"))),
// HOL-FIRST-ADMIN: a new invite minted here would open nothing on the site; its main mints one.
Ok(FirstDoor::Closed(why)) => {
drop(_pen);
return by_main(state, &name, &run, &to_given, &format!("no longer takes the custody's first sign-in invite ({})", masked_in(&why)));
}
Err(busy) => return Err(busy),
}
let now = state.now();
let p = run.phase.clone();
run.email = to.clone();
run.told = false;
run.history.push(Transition {
phase: p,
at_ms: now,
note: format!(
"first sign-in link re-sent by the operator to {}",
masked(&to)
),
});
save(state, &run).map_err(StartRefusal::NotSold)?;
// The ready mail again, to the new address, with the custody's link (it saves the run).
super::tell(state, &mut run);
eprintln!("monetize-server: site {name}: the operator re-sent its first sign-in link to {} (sent: {})", masked(&to), run.told);
if run.told {
Ok(said(format!("{name}'s first sign-in link is mailed to {} again; it works once, until the site's first admin signs in.", masked(&to))))
} else {
Ok(said(format!("{name}'s first sign-in address is now {}; the mail did not go yet and is sent again within the hour.", masked(&to))))
}
}