feat: refuse to learn a first-contact key from an unpinned server
Adds an opt-in "require a pinned server" setting that gates the one RESOLVE path that currently trusts whatever key a server hands back for a brand-new, hand-typed address — self-certifying addresses and already-known contacts are structurally exempt. A refusal shows an inline recovery card in compose to fetch, compare, and pin the key without losing the draft. Also closes two adjacent gaps: a self-certifying address could silently overwrite an already-trusted contact's key (now asks, showing both fingerprints), and a contact's detail view now names its server and pin state.
This commit is contained in:
parent
84397a3fdd
commit
80aca8a29f
4 changed files with 192 additions and 10 deletions
|
|
@ -143,6 +143,21 @@
|
|||
<input name="to" required spellcheck="false" placeholder="to: alice@example.org or smol://…">
|
||||
<input name="subject" spellcheck="false" placeholder="subject">
|
||||
<textarea name="body" rows="12" placeholder="message"></textarea>
|
||||
<div id="compose-unpinned" class="seed-card" hidden>
|
||||
<h4>unpinned server</h4>
|
||||
<p class="hint">
|
||||
<strong id="compose-unpinned-host"></strong> is not pinned, and "require a pinned
|
||||
server" refuses to trust a key fetched from it for a new recipient. Fetch its key,
|
||||
compare the fingerprint against what the operator published through a trusted
|
||||
channel, then pin it to send.
|
||||
</p>
|
||||
<div id="compose-unpinned-key-area" hidden></div>
|
||||
<div class="actions">
|
||||
<button type="button" id="compose-unpinned-fetch">Fetch their server's key</button>
|
||||
<button type="button" id="compose-unpinned-pin" class="filled" hidden>Pin and send</button>
|
||||
</div>
|
||||
<span id="compose-unpinned-error" class="error"></span>
|
||||
</div>
|
||||
<footer>
|
||||
<label class="anon"><input type="checkbox" name="anonymous"> anonymous — omit my address</label>
|
||||
<span id="compose-error" class="error"></span>
|
||||
|
|
@ -211,6 +226,17 @@
|
|||
</section>
|
||||
|
||||
<section class="panel" data-panel="advanced" hidden>
|
||||
<h3>trust</h3>
|
||||
<label class="check-row">
|
||||
<input type="checkbox" id="require-pinned-server">
|
||||
<span>
|
||||
<span class="check-title">Require a pinned server</span>
|
||||
<span class="hint">Refuse to look up a new recipient's key from a server you haven't
|
||||
pinned. An address that already carries a key, or a recipient you already know, is
|
||||
unaffected — this only applies to a new, hand-typed address.</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<h3>rotations</h3>
|
||||
<p id="rotations-description" class="hint">Issues a fresh key from your secret with a signed
|
||||
certificate proving it replaces this one. Contacts accept the change from that chain, and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue