import { pgTable, serial, varchar, boolean, integer, bigint, real } from "drizzle-orm/pg-core"; import { InferSelectModel } from "drizzle-orm"; export const domains = pgTable("domains", { domainId: varchar("domainId").primaryKey(), baseDomain: varchar("baseDomain").notNull(), configManaged: boolean("configManaged").notNull().default(false) }); export const orgs = pgTable("orgs", { orgId: varchar("orgId").primaryKey(), name: varchar("name").notNull() }); export const orgDomains = pgTable("orgDomains", { orgId: varchar("orgId") .notNull() .references(() => orgs.orgId, { onDelete: "cascade" }), domainId: varchar("domainId") .notNull() .references(() => domains.domainId, { onDelete: "cascade" }) }); export const sites = pgTable("sites", { siteId: serial("siteId").primaryKey(), orgId: varchar("orgId") .references(() => orgs.orgId, { onDelete: "cascade" }) .notNull(), niceId: varchar("niceId").notNull(), exitNodeId: integer("exitNode").references(() => exitNodes.exitNodeId, { onDelete: "set null" }), name: varchar("name").notNull(), pubKey: varchar("pubKey"), subnet: varchar("subnet").notNull(), megabytesIn: real("bytesIn"), megabytesOut: real("bytesOut"), lastBandwidthUpdate: varchar("lastBandwidthUpdate"), type: varchar("type").notNull(), // "newt" or "wireguard" online: boolean("online").notNull().default(false), dockerSocketEnabled: boolean("dockerSocketEnabled").notNull().default(true) }); export const resources = pgTable("resources", { resourceId: serial("resourceId").primaryKey(), siteId: integer("siteId") .references(() => sites.siteId, { onDelete: "cascade" }) .notNull(), orgId: varchar("orgId") .references(() => orgs.orgId, { onDelete: "cascade" }) .notNull(), name: varchar("name").notNull(), subdomain: varchar("subdomain"), fullDomain: varchar("fullDomain"), domainId: varchar("domainId").references(() => domains.domainId, { onDelete: "set null" }), ssl: boolean("ssl").notNull().default(false), blockAccess: boolean("blockAccess").notNull().default(false), sso: boolean("sso").notNull().default(true), http: boolean("http").notNull().default(true), protocol: varchar("protocol").notNull(), proxyPort: integer("proxyPort"), emailWhitelistEnabled: boolean("emailWhitelistEnabled") .notNull() .default(false), isBaseDomain: boolean("isBaseDomain"), applyRules: boolean("applyRules").notNull().default(false), enabled: boolean("enabled").notNull().default(true), stickySession: boolean("stickySession").notNull().default(false), tlsServerName: varchar("tlsServerName"), setHostHeader: varchar("setHostHeader") }); export const targets = pgTable("targets", { targetId: serial("targetId").primaryKey(), resourceId: integer("resourceId") .references(() => resources.resourceId, { onDelete: "cascade" }) .notNull(), ip: varchar("ip").notNull(), method: varchar("method"), port: integer("port").notNull(), internalPort: integer("internalPort"), enabled: boolean("enabled").notNull().default(true) }); export const exitNodes = pgTable("exitNodes", { exitNodeId: serial("exitNodeId").primaryKey(), name: varchar("name").notNull(), address: varchar("address").notNull(), endpoint: varchar("endpoint").notNull(), publicKey: varchar("publicKey").notNull(), listenPort: integer("listenPort").notNull(), reachableAt: varchar("reachableAt") }); export const users = pgTable("user", { userId: varchar("id").primaryKey(), email: varchar("email"), username: varchar("username").notNull(), name: varchar("name"), type: varchar("type").notNull(), // "internal", "oidc" idpId: integer("idpId").references(() => idp.idpId, { onDelete: "cascade" }), passwordHash: varchar("passwordHash"), twoFactorEnabled: boolean("twoFactorEnabled").notNull().default(false), twoFactorSecret: varchar("twoFactorSecret"), emailVerified: boolean("emailVerified").notNull().default(false), dateCreated: varchar("dateCreated").notNull(), serverAdmin: boolean("serverAdmin").notNull().default(false) }); export const newts = pgTable("newt", { newtId: varchar("id").primaryKey(), secretHash: varchar("secretHash").notNull(), dateCreated: varchar("dateCreated").notNull(), siteId: integer("siteId").references(() => sites.siteId, { onDelete: "cascade" }) }); export const twoFactorBackupCodes = pgTable("twoFactorBackupCodes", { codeId: serial("id").primaryKey(), userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), codeHash: varchar("codeHash").notNull() }); export const sessions = pgTable("session", { sessionId: varchar("id").primaryKey(), userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), expiresAt: bigint("expiresAt", { mode: "number" }).notNull() }); export const newtSessions = pgTable("newtSession", { sessionId: varchar("id").primaryKey(), newtId: varchar("newtId") .notNull() .references(() => newts.newtId, { onDelete: "cascade" }), expiresAt: bigint("expiresAt", { mode: "number" }).notNull() }); export const userOrgs = pgTable("userOrgs", { userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), orgId: varchar("orgId") .references(() => orgs.orgId, { onDelete: "cascade" }) .notNull(), roleId: integer("roleId") .notNull() .references(() => roles.roleId), isOwner: boolean("isOwner").notNull().default(false) }); export const emailVerificationCodes = pgTable("emailVerificationCodes", { codeId: serial("id").primaryKey(), userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), email: varchar("email").notNull(), code: varchar("code").notNull(), expiresAt: bigint("expiresAt", { mode: "number" }).notNull() }); export const passwordResetTokens = pgTable("passwordResetTokens", { tokenId: serial("id").primaryKey(), email: varchar("email").notNull(), userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), tokenHash: varchar("tokenHash").notNull(), expiresAt: bigint("expiresAt", { mode: "number" }).notNull() }); export const actions = pgTable("actions", { actionId: varchar("actionId").primaryKey(), name: varchar("name"), description: varchar("description") }); export const roles = pgTable("roles", { roleId: serial("roleId").primaryKey(), orgId: varchar("orgId") .references(() => orgs.orgId, { onDelete: "cascade" }) .notNull(), isAdmin: boolean("isAdmin"), name: varchar("name").notNull(), description: varchar("description") }); export const roleActions = pgTable("roleActions", { roleId: integer("roleId") .notNull() .references(() => roles.roleId, { onDelete: "cascade" }), actionId: varchar("actionId") .notNull() .references(() => actions.actionId, { onDelete: "cascade" }), orgId: varchar("orgId") .notNull() .references(() => orgs.orgId, { onDelete: "cascade" }) }); export const userActions = pgTable("userActions", { userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), actionId: varchar("actionId") .notNull() .references(() => actions.actionId, { onDelete: "cascade" }), orgId: varchar("orgId") .notNull() .references(() => orgs.orgId, { onDelete: "cascade" }) }); export const roleSites = pgTable("roleSites", { roleId: integer("roleId") .notNull() .references(() => roles.roleId, { onDelete: "cascade" }), siteId: integer("siteId") .notNull() .references(() => sites.siteId, { onDelete: "cascade" }) }); export const userSites = pgTable("userSites", { userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), siteId: integer("siteId") .notNull() .references(() => sites.siteId, { onDelete: "cascade" }) }); export const roleResources = pgTable("roleResources", { roleId: integer("roleId") .notNull() .references(() => roles.roleId, { onDelete: "cascade" }), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }) }); export const userResources = pgTable("userResources", { userId: varchar("userId") .notNull() .references(() => users.userId, { onDelete: "cascade" }), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }) }); export const limitsTable = pgTable("limits", { limitId: serial("limitId").primaryKey(), orgId: varchar("orgId") .references(() => orgs.orgId, { onDelete: "cascade" }) .notNull(), name: varchar("name").notNull(), value: bigint("value", { mode: "number" }).notNull(), description: varchar("description") }); export const userInvites = pgTable("userInvites", { inviteId: varchar("inviteId").primaryKey(), orgId: varchar("orgId") .notNull() .references(() => orgs.orgId, { onDelete: "cascade" }), email: varchar("email").notNull(), expiresAt: bigint("expiresAt", { mode: "number" }).notNull(), tokenHash: varchar("token").notNull(), roleId: integer("roleId") .notNull() .references(() => roles.roleId, { onDelete: "cascade" }) }); export const resourcePincode = pgTable("resourcePincode", { pincodeId: serial("pincodeId").primaryKey(), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }), pincodeHash: varchar("pincodeHash").notNull(), digitLength: integer("digitLength").notNull() }); export const resourcePassword = pgTable("resourcePassword", { passwordId: serial("passwordId").primaryKey(), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }), passwordHash: varchar("passwordHash").notNull() }); export const resourceAccessToken = pgTable("resourceAccessToken", { accessTokenId: varchar("accessTokenId").primaryKey(), orgId: varchar("orgId") .notNull() .references(() => orgs.orgId, { onDelete: "cascade" }), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }), tokenHash: varchar("tokenHash").notNull(), sessionLength: bigint("sessionLength", { mode: "number" }).notNull(), expiresAt: bigint("expiresAt", { mode: "number" }), title: varchar("title"), description: varchar("description"), createdAt: bigint("createdAt", { mode: "number" }).notNull() }); export const resourceSessions = pgTable("resourceSessions", { sessionId: varchar("id").primaryKey(), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }), expiresAt: bigint("expiresAt", { mode: "number" }).notNull(), sessionLength: bigint("sessionLength", { mode: "number" }).notNull(), doNotExtend: boolean("doNotExtend").notNull().default(false), isRequestToken: boolean("isRequestToken"), userSessionId: varchar("userSessionId").references( () => sessions.sessionId, { onDelete: "cascade" } ), passwordId: integer("passwordId").references( () => resourcePassword.passwordId, { onDelete: "cascade" } ), pincodeId: integer("pincodeId").references( () => resourcePincode.pincodeId, { onDelete: "cascade" } ), whitelistId: integer("whitelistId").references( () => resourceWhitelist.whitelistId, { onDelete: "cascade" } ), accessTokenId: varchar("accessTokenId").references( () => resourceAccessToken.accessTokenId, { onDelete: "cascade" } ) }); export const resourceWhitelist = pgTable("resourceWhitelist", { whitelistId: serial("id").primaryKey(), email: varchar("email").notNull(), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }) }); export const resourceOtp = pgTable("resourceOtp", { otpId: serial("otpId").primaryKey(), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }), email: varchar("email").notNull(), otpHash: varchar("otpHash").notNull(), expiresAt: bigint("expiresAt", { mode: "number" }).notNull() }); export const versionMigrations = pgTable("versionMigrations", { version: varchar("version").primaryKey(), executedAt: bigint("executedAt", { mode: "number" }).notNull() }); export const resourceRules = pgTable("resourceRules", { ruleId: serial("ruleId").primaryKey(), resourceId: integer("resourceId") .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }), enabled: boolean("enabled").notNull().default(true), priority: integer("priority").notNull(), action: varchar("action").notNull(), // ACCEPT, DROP match: varchar("match").notNull(), // CIDR, PATH, IP value: varchar("value").notNull() }); export const supporterKey = pgTable("supporterKey", { keyId: serial("keyId").primaryKey(), key: varchar("key").notNull(), githubUsername: varchar("githubUsername").notNull(), phrase: varchar("phrase"), tier: varchar("tier"), valid: boolean("valid").notNull().default(false) }); export const idp = pgTable("idp", { idpId: serial("idpId").primaryKey(), name: varchar("name").notNull(), type: varchar("type").notNull(), defaultRoleMapping: varchar("defaultRoleMapping"), defaultOrgMapping: varchar("defaultOrgMapping"), autoProvision: boolean("autoProvision").notNull().default(false) }); export const idpOidcConfig = pgTable("idpOidcConfig", { idpOauthConfigId: serial("idpOauthConfigId").primaryKey(), idpId: integer("idpId") .notNull() .references(() => idp.idpId, { onDelete: "cascade" }), clientId: varchar("clientId").notNull(), clientSecret: varchar("clientSecret").notNull(), authUrl: varchar("authUrl").notNull(), tokenUrl: varchar("tokenUrl").notNull(), identifierPath: varchar("identifierPath").notNull(), emailPath: varchar("emailPath"), namePath: varchar("namePath"), scopes: varchar("scopes").notNull() }); export const licenseKey = pgTable("licenseKey", { licenseKeyId: varchar("licenseKeyId").primaryKey().notNull(), instanceId: varchar("instanceId").notNull(), token: varchar("token").notNull() }); export const hostMeta = pgTable("hostMeta", { hostMetaId: varchar("hostMetaId").primaryKey().notNull(), createdAt: bigint("createdAt", { mode: "number" }).notNull() }); export const apiKeys = pgTable("apiKeys", { apiKeyId: varchar("apiKeyId").primaryKey(), name: varchar("name").notNull(), apiKeyHash: varchar("apiKeyHash").notNull(), lastChars: varchar("lastChars").notNull(), createdAt: varchar("dateCreated").notNull(), isRoot: boolean("isRoot").notNull().default(false) }); export const apiKeyActions = pgTable("apiKeyActions", { apiKeyId: varchar("apiKeyId") .notNull() .references(() => apiKeys.apiKeyId, { onDelete: "cascade" }), actionId: varchar("actionId") .notNull() .references(() => actions.actionId, { onDelete: "cascade" }) }); export const apiKeyOrg = pgTable("apiKeyOrg", { apiKeyId: varchar("apiKeyId") .notNull() .references(() => apiKeys.apiKeyId, { onDelete: "cascade" }), orgId: varchar("orgId") .references(() => orgs.orgId, { onDelete: "cascade" }) .notNull() }); export const idpOrg = pgTable("idpOrg", { idpId: integer("idpId") .notNull() .references(() => idp.idpId, { onDelete: "cascade" }), orgId: varchar("orgId") .notNull() .references(() => orgs.orgId, { onDelete: "cascade" }), roleMapping: varchar("roleMapping"), orgMapping: varchar("orgMapping") }); export type Org = InferSelectModel; export type User = InferSelectModel; export type Site = InferSelectModel; export type Resource = InferSelectModel; export type ExitNode = InferSelectModel; export type Target = InferSelectModel; export type Session = InferSelectModel; export type Newt = InferSelectModel; export type NewtSession = InferSelectModel; export type EmailVerificationCode = InferSelectModel< typeof emailVerificationCodes >; export type TwoFactorBackupCode = InferSelectModel; export type PasswordResetToken = InferSelectModel; export type Role = InferSelectModel; export type Action = InferSelectModel; export type RoleAction = InferSelectModel; export type UserAction = InferSelectModel; export type RoleSite = InferSelectModel; export type UserSite = InferSelectModel; export type RoleResource = InferSelectModel; export type UserResource = InferSelectModel; export type Limit = InferSelectModel; export type UserInvite = InferSelectModel; export type UserOrg = InferSelectModel; export type ResourceSession = InferSelectModel; export type ResourcePincode = InferSelectModel; export type ResourcePassword = InferSelectModel; export type ResourceOtp = InferSelectModel; export type ResourceAccessToken = InferSelectModel; export type ResourceWhitelist = InferSelectModel; export type VersionMigration = InferSelectModel; export type ResourceRule = InferSelectModel; export type Domain = InferSelectModel; export type SupporterKey = InferSelectModel; export type Idp = InferSelectModel; export type ApiKey = InferSelectModel; export type ApiKeyAction = InferSelectModel; export type ApiKeyOrg = InferSelectModel;