mirror of
https://github.com/tale/headplane.git
synced 2026-07-27 16:18:57 +00:00
684a95b5e8
Security: - Add unique constraint on headscale_user_id to prevent hijacking - linkHeadscaleUser now rejects already-claimed Headscale users - Onboarding dropdown filters out claimed users - onboarding-skip action redirects on rejected claims Maintenance: - Replace probabilistic session pruning with setInterval (15m) - Move pruning out of request path into server startup Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019cce57-c9e1-7732-9709-8288127573a9
51 lines
2.0 KiB
TypeScript
51 lines
2.0 KiB
TypeScript
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
|
|
|
import { HostInfo } from "~/types";
|
|
|
|
export const ephemeralNodes = sqliteTable("ephemeral_nodes", {
|
|
auth_key: text("auth_key").primaryKey(),
|
|
node_key: text("node_key"),
|
|
});
|
|
|
|
export type EphemeralNode = typeof ephemeralNodes.$inferSelect;
|
|
export type EphemeralNodeInsert = typeof ephemeralNodes.$inferInsert;
|
|
|
|
export const hostInfo = sqliteTable("host_info", {
|
|
host_id: text("host_id").primaryKey(),
|
|
payload: text("payload", { mode: "json" }).$type<HostInfo>(),
|
|
updated_at: integer("updated_at", { mode: "timestamp" }).$default(() => new Date()),
|
|
});
|
|
|
|
export type HostInfoRecord = typeof hostInfo.$inferSelect;
|
|
export type HostInfoInsert = typeof hostInfo.$inferInsert;
|
|
|
|
export const users = sqliteTable("users", {
|
|
id: text("id").primaryKey(),
|
|
sub: text("sub").notNull().unique(),
|
|
role: text("role").notNull().default("member"),
|
|
headscale_user_id: text("headscale_user_id").unique(),
|
|
onboarded: integer("onboarded", { mode: "boolean" }).notNull().default(false),
|
|
created_at: integer("created_at", { mode: "timestamp" }).$default(() => new Date()),
|
|
updated_at: integer("updated_at", { mode: "timestamp" }).$default(() => new Date()),
|
|
last_login_at: integer("last_login_at", { mode: "timestamp" }),
|
|
|
|
// Deprecated: kept for migration compatibility, will be removed in 1.0
|
|
caps: integer("caps").notNull().default(0),
|
|
});
|
|
|
|
export type HeadplaneUser = typeof users.$inferSelect;
|
|
export type HeadplaneUserInsert = typeof users.$inferInsert;
|
|
|
|
export const authSessions = sqliteTable("auth_sessions", {
|
|
id: text("id").primaryKey(),
|
|
kind: text("kind").notNull(), // 'oidc' | 'api_key'
|
|
user_id: text("user_id"),
|
|
api_key_hash: text("api_key_hash"),
|
|
api_key_display: text("api_key_display"),
|
|
expires_at: integer("expires_at", { mode: "timestamp" }).notNull(),
|
|
created_at: integer("created_at", { mode: "timestamp" }).$default(() => new Date()),
|
|
});
|
|
|
|
export type AuthSessionRecord = typeof authSessions.$inferSelect;
|
|
export type AuthSessionInsert = typeof authSessions.$inferInsert;
|