46decf351fc0
offer the setup key and address with copy buttons, and no QR (v3.2.3)
- time
- 2026-10-08 21:55 UTC · 4 days ago
- machine
- Junes-MacBook-Pro.local
- agent
- deepseek-flash
- session
- two-step sign-in
- parent
- 0b513e91a395
↓ kepr-46decf35.tar.gzatlas at this save
files changed3 files
package.json+1 −1src/admin/account.ts+8 −5tests/account.test.ts+6 −0package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "kepr",3- "version": "3.2.2",3+ "version": "3.2.3",44 "private": true,55 "type": "module",66 "scripts": {src/admin/account.ts+8 −5
@@ -82,11 +82,14 @@8282 // typed it holds it, so a tampered field can only fail.8383 const twoStep =8484 offered !== ""85- ? html`<p>Add this key to an authenticator app by hand, or paste the address under it, then86-type the code the app shows. The key is shown this once; from then on sign-in asks for the password87-and a code.</p>88-<p class="issue-meta mono">key: ${offered}</p>89-<p class="issue-meta mono">${otpauthUri(offered, ctx.domain)}</p>85+ ? html`<p>Add this key to an authenticator app by hand, or open the address below on a phone86+that has one, then type the code the app shows. The key is shown this once; from then on sign-in87+asks for the password and a code.</p>88+<p class="issue-meta mono">key: ${offered}89+<button type="button" class="copy-btn" data-copy="${offered}" hidden>copy key</button></p>90+<p class="issue-meta mono"><a href="${otpauthUri(offered, ctx.domain)}">open in an authenticator app</a>91+<button type="button" class="copy-btn" data-copy="${otpauthUri(offered, ctx.domain)}" hidden>copy the92+setup address</button></p>9093 <form class="issues-form" method="post" action="/admin/account">9194 ${formField(c)}<input type="hidden" name="action" value="totp-confirm">9295 <input type="hidden" name="secret" value="${offered}">tests/account.test.ts+6 −0
@@ -130,6 +130,12 @@130130 const secret = /key: ([A-Z2-7]{32})/.exec(offered)?.[1] ?? "";131131 expect(secret).toHaveLength(32);132132 expect(offered).toContain("otpauth://totp/kepr:kepr.example");133+ // Both the key and the setup address can be copied, and the address opens an app directly.134+ expect(offered).toContain(`data-copy="${secret}"`);135+ expect(offered).toContain(`data-copy="otpauth://totp/kepr:kepr.example?secret=${secret}`);136+ expect(offered).toContain(`href="otpauth://totp/kepr:kepr.example?secret=${secret}`);137+ // The html the template writes escapes the ampersands the address carries.138+ expect(offered).toContain("&issuer=kepr");133139 expect(inst.config.totpSecret).toBeUndefined();134140 const wrong = await operator.post("/admin/account", {135141 action: "totp-confirm",