diff --git a/web/index.html b/web/index.html
index c0f7425..465a73c 100644
--- a/web/index.html
+++ b/web/index.html
@@ -94,7 +94,7 @@
1 your server
Pin the key of the server that will hold your mail. Get it from its operator over a
- channel you already trust — registering and fetching both refuse an unpinned server (SPEC.md §4).
+ channel you already trust — registering, recalling and fetching all refuse an unpinned server (SPEC.md §4).
+
+ already registered elsewhere?
+ Restoring a seed brings back the identity, not the memory of what address it was
+ registered under in a different browser — the server was never asked. Recall it here: this
+ looks the address up and checks it resolves to this identity's key, without registering anything.
+
+
diff --git a/web/js/app.js b/web/js/app.js
index 7e89968..8e20b03 100644
--- a/web/js/app.js
+++ b/web/js/app.js
@@ -883,6 +883,37 @@ $("register-form").onsubmit = async (event) => {
}
};
+// Restoring a seed brings back the identity, not the memory of what address a
+// *different* browser registered it under — "account" is local-only state,
+// never asked of the server. This binds it without REGISTER: RESOLVE the
+// address and require it name this exact key, so a typo or someone else's
+// address can't silently misfile outgoing Reply-To / fetch under it.
+$("recall-form").onsubmit = async (event) => {
+ event.preventDefault();
+ const form = event.target;
+ try {
+ const me = store.identity();
+ if (!me) throw new SmolError("no identity yet");
+ const addr = parseAddress(form.address.value.trim());
+ const opened = await connect(addr, { requirePin: true });
+ let current;
+ try {
+ ({ identity: current } = await resolveOp(opened.session, addr.user));
+ } finally {
+ opened.session.stream.close();
+ }
+ if (!timingSafeEqual(current, me.publicKey))
+ throw new SmolError(`${addr.short} resolves to a different key — not this identity`);
+ store.setAccount(addr);
+ status(`recalled ${addr.short}\nshare: ${addr.uri(me.publicKey)}`);
+ renderAccount();
+ renderSettings();
+ form.reset();
+ } catch (err) {
+ status(err.message, true);
+ }
+};
+
async function rotateIdentity() {
const me = store.identity();
const addr = accountAddress();