Files
hamlab/web/src/guest.ts
T
Mitchell-JohnsonandClaude Opus 5 179f342a2c A guest login is a full account with a clock on it
Mitchell, on the read-only version built earlier today: scratch it. He hands
these to people he trusts and revokes them otherwise, so a console with half
its tabs missing solved a problem he doesn't have.

So the allow-list, the middleware check and every "not for a guest" branch in
the UI are gone. What is left is the part that was the point: a throwaway
account that expires by itself, is checked on every request, swept once a
minute, and can be ended in one tap. A guest now gets the whole console on
every machine, terminal included.

Said once, since it is his call and he has made it: that means a guest has a
root-capable shell on every host, and can make an account or a token of its own
that outlives the guest login.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 17:53:55 -07:00

25 lines
1.0 KiB
TypeScript

// A guest login's clock. That is the whole difference between a guest and an account: it
// can do everything, until it can't, so what the console has to show is how long is left.
import { useEffect, useState } from 'react'
// fmtLeft says how long is left, in the roundest terms that are still honest.
export function fmtLeft(ms: number): string {
const min = Math.floor(ms / 60000)
if (min >= 120) return `${Math.floor(min / 60)} h ${min % 60} min`
if (min >= 1) return `${min} min`
return 'under a minute'
}
// useTimeLeft is the milliseconds until `until`, re-rendering the caller every 15 seconds so
// the number keeps up. 0 when there is no expiry, which is every normal account.
export function useTimeLeft(until?: string): number {
const [, tick] = useState(0)
const active = !!until
useEffect(() => {
if (!active) return
const t = setInterval(() => tick((n) => n + 1), 15000)
return () => clearInterval(t)
}, [active])
return until ? Math.max(0, new Date(until).getTime() - Date.now()) : 0
}