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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8a7167bf03
commit
179f342a2c
+7
-25
@@ -1,27 +1,7 @@
|
||||
// Whether this console is being looked at through a guest login, kept here so any page can
|
||||
// ask without it being threaded through every prop. Set from /api/me when the app loads.
|
||||
//
|
||||
// This is politeness, not security: a guest is stopped by the server, which answers 403 to
|
||||
// everything but the handful of reads it allows (internal/api/guests.go). What it buys is a
|
||||
// console that doesn't offer a visitor buttons that would only fail.
|
||||
// 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'
|
||||
|
||||
let guest = false
|
||||
let until = ''
|
||||
|
||||
export function setGuest(on: boolean, expires?: string) {
|
||||
guest = on
|
||||
until = expires ?? ''
|
||||
}
|
||||
|
||||
export const isGuest = () => guest
|
||||
|
||||
// msLeft is how long this guest login has, or null when it isn't one.
|
||||
export function msLeft(): number | null {
|
||||
if (!guest || !until) return null
|
||||
return Math.max(0, new Date(until).getTime() - Date.now())
|
||||
}
|
||||
|
||||
// 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)
|
||||
@@ -30,13 +10,15 @@ export function fmtLeft(ms: number): string {
|
||||
return 'under a minute'
|
||||
}
|
||||
|
||||
// useCountdown re-renders the caller every 15 seconds, for a clock that has to keep up.
|
||||
export function useCountdown(active: boolean): number {
|
||||
// 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 msLeft() ?? 0
|
||||
return until ? Math.max(0, new Date(until).getTime() - Date.now()) : 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user