hop2 0.11.15 → 0.11.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -320,6 +320,44 @@ hop client ./credentials.json
320
320
 
321
321
  First run prompts for password setup and TOTP enrollment, then the user logs in at their assigned URL such as `https://alice.hop.yourdomain.com`.
322
322
 
323
+ ### Self-service signup (optional)
324
+
325
+ Instead of adding every user by hand, the landing host can serve a public
326
+ signup page. Visitors ask for a subdomain, confirm an email address on a
327
+ domain you nominate, and wait for you to approve — approval runs the same
328
+ `hop user add` + `hop user export` provisioning as the manual flow, then
329
+ emails them a one-time link to collect their credentials.
330
+
331
+ ```bash
332
+ hop mail setup # SMTP (a Gmail App Password works)
333
+ hop registration admin jianzhou # reserve your own subdomain
334
+ hop registration domain uchicago.edu
335
+ hop registration enable
336
+ ```
337
+
338
+ Then review requests as they arrive:
339
+
340
+ ```bash
341
+ hop user pending
342
+ hop user approve alice
343
+ hop user reject bob "please use your own name"
344
+ ```
345
+
346
+ Notes:
347
+
348
+ - Off by default. Enabling it makes the bare hostname public; your own
349
+ browser keeps working while its session cookie is valid, and
350
+ `https://<landing-host>/signin` always reaches the login page.
351
+ - Nothing runs on your machine for them. A registrant gets a Cloudflare
352
+ tunnel and a DNS record; hop itself runs on *their* computer, with their
353
+ own password and TOTP.
354
+ - The tunnel lives in **your** Cloudflare account and the subdomain is under
355
+ **your** domain, so an approved user can serve anything they like at
356
+ `their-name.your-domain`. Approve people you would vouch for, and use
357
+ `hop user remove <name>` to revoke (delete the DNS record by hand).
358
+ - Registrations live in `~/.hop2/.registrations.json` (0600). Verification
359
+ and claim links are stored only as hashes.
360
+
323
361
  ### Security
324
362
 
325
363
  - Password + TOTP is supported; password is required for custom domains
@@ -116,6 +116,17 @@ export const createVoiceHold = (opts: VoiceHoldOptions) => {
116
116
  * undefined — not a voice-relevant event; continue with other branches.
117
117
  */
118
118
  const handleKey = (ev: { type: string; code: string; key: string; repeat?: boolean; metaKey?: boolean; ctrlKey?: boolean; altKey?: boolean; shiftKey?: boolean }): boolean | undefined => {
119
+ // Return, mid-dictation, ENDS it and keeps the words (Jian). Without
120
+ // this the Enter fell through to the terminal while the recogniser was
121
+ // still running: a bare newline hit the composer, and the transcript
122
+ // landed after it — the one key you would reach for to finish a thought
123
+ // was the one that split it in half. Swallowed rather than passed on, so
124
+ // this inserts and does not also submit; a second Return sends it.
125
+ if (active && ev.type === "keydown" && (ev.key === "Enter" || ev.code === "Enter"
126
+ || ev.code === "NumpadEnter")) {
127
+ stop();
128
+ return false;
129
+ }
119
130
  if (ev.code === "Space" && !ev.metaKey && !ev.ctrlKey && !ev.altKey && !ev.shiftKey
120
131
  && !!speechRecognitionCtor() && (active || opts.eligible())) {
121
132
  if (ev.type === "keydown") {