Files
netris-nestri/packages/core/src/machine/install-token.sql.ts
T
Wanjohi f691b56c0c feat(core): one-time install tokens that register a host to a team
Installing on a host should be a command a person pastes, not a user
session copied onto a machine. A token is issued for a team, spent by its
first use, expires after an hour and is stored only as a digest, because
it travels in that command and so lands in shell history.

Redeeming is one conditional update inside the registration transaction:
concurrent redemptions of one token register exactly one machine, and a
registration that fails leaves the token unspent.
2026-09-28 08:36:09 +03:00

41 lines
1.5 KiB
TypeScript

import { index, pgTable, text, uniqueIndex } from 'drizzle-orm/pg-core';
import { id, timestamps, ulid, utc } from '../db/types.js';
import { TeamTable } from '../team/team.sql.js';
import { UserTable } from '../user/user.sql.js';
import { MachineTable } from './machine.sql.js';
/**
* A one-time credential that registers exactly one machine to one team.
*
* It exists so that installing on a host is a command a person pastes, rather
* than a user session copied onto a machine. It travels in that command, so it
* lands in shell history: that is why it is single-use, expires in minutes,
* and is stored only as a digest.
*/
export const InstallTokenTable = pgTable(
'install_token',
{
...id,
...timestamps,
teamId: ulid('team_id')
.notNull()
.references(() => TeamTable.id, { onDelete: 'cascade' }),
// Who asked for it. They become the machine's owner, as they would have
// by registering it with their own session.
createdByUserId: ulid('created_by_user_id')
.notNull()
.references(() => UserTable.id, { onDelete: 'cascade' }),
tokenHash: text('token_hash').notNull(),
expiresAt: utc('expires_at').notNull(),
redeemedAt: utc('redeemed_at'),
// The machine it made. Null until redeemed; kept afterwards so a support
// conversation can say which command produced which host.
machineId: ulid('machine_id').references(() => MachineTable.id, { onDelete: 'set null' })
},
(t) => [
uniqueIndex('install_token_hash_unique').on(t.tokenHash),
index('install_token_team_idx').on(t.teamId)
]
);