schema.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. import { InferSelectModel } from "drizzle-orm";
  2. import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
  3. export const orgs = sqliteTable("orgs", {
  4. orgId: text("orgId").primaryKey(),
  5. name: text("name").notNull(),
  6. domain: text("domain").notNull()
  7. });
  8. export const sites = sqliteTable("sites", {
  9. siteId: integer("siteId").primaryKey({ autoIncrement: true }),
  10. orgId: text("orgId")
  11. .references(() => orgs.orgId, {
  12. onDelete: "cascade"
  13. })
  14. .notNull(),
  15. niceId: text("niceId").notNull(),
  16. exitNodeId: integer("exitNode").references(() => exitNodes.exitNodeId, {
  17. onDelete: "set null"
  18. }),
  19. name: text("name").notNull(),
  20. pubKey: text("pubKey"),
  21. subnet: text("subnet").notNull(),
  22. megabytesIn: integer("bytesIn"),
  23. megabytesOut: integer("bytesOut"),
  24. lastBandwidthUpdate: text("lastBandwidthUpdate"),
  25. type: text("type").notNull(), // "newt" or "wireguard"
  26. online: integer("online", { mode: "boolean" }).notNull().default(false)
  27. });
  28. export const resources = sqliteTable("resources", {
  29. resourceId: integer("resourceId").primaryKey({ autoIncrement: true }),
  30. siteId: integer("siteId")
  31. .references(() => sites.siteId, {
  32. onDelete: "cascade"
  33. })
  34. .notNull(),
  35. orgId: text("orgId")
  36. .references(() => orgs.orgId, {
  37. onDelete: "cascade"
  38. })
  39. .notNull(),
  40. name: text("name").notNull(),
  41. subdomain: text("subdomain"),
  42. fullDomain: text("fullDomain"),
  43. ssl: integer("ssl", { mode: "boolean" }).notNull().default(false),
  44. blockAccess: integer("blockAccess", { mode: "boolean" })
  45. .notNull()
  46. .default(false),
  47. sso: integer("sso", { mode: "boolean" }).notNull().default(true),
  48. http: integer("http", { mode: "boolean" }).notNull().default(true),
  49. protocol: text("protocol").notNull(),
  50. proxyPort: integer("proxyPort"),
  51. emailWhitelistEnabled: integer("emailWhitelistEnabled", { mode: "boolean" })
  52. .notNull()
  53. .default(false),
  54. isBaseDomain: integer("isBaseDomain", { mode: "boolean" })
  55. });
  56. export const targets = sqliteTable("targets", {
  57. targetId: integer("targetId").primaryKey({ autoIncrement: true }),
  58. resourceId: integer("resourceId")
  59. .references(() => resources.resourceId, {
  60. onDelete: "cascade"
  61. })
  62. .notNull(),
  63. ip: text("ip").notNull(),
  64. method: text("method"),
  65. port: integer("port").notNull(),
  66. internalPort: integer("internalPort"),
  67. enabled: integer("enabled", { mode: "boolean" }).notNull().default(true)
  68. });
  69. export const exitNodes = sqliteTable("exitNodes", {
  70. exitNodeId: integer("exitNodeId").primaryKey({ autoIncrement: true }),
  71. name: text("name").notNull(),
  72. address: text("address").notNull(), // this is the address of the wireguard interface in gerbil
  73. endpoint: text("endpoint").notNull(), // this is how to reach gerbil externally - gets put into the wireguard config
  74. publicKey: text("pubicKey").notNull(),
  75. listenPort: integer("listenPort").notNull(),
  76. reachableAt: text("reachableAt") // this is the internal address of the gerbil http server for command control
  77. });
  78. export const users = sqliteTable("user", {
  79. userId: text("id").primaryKey(),
  80. email: text("email").notNull().unique(),
  81. passwordHash: text("passwordHash").notNull(),
  82. twoFactorEnabled: integer("twoFactorEnabled", { mode: "boolean" })
  83. .notNull()
  84. .default(false),
  85. twoFactorSecret: text("twoFactorSecret"),
  86. emailVerified: integer("emailVerified", { mode: "boolean" })
  87. .notNull()
  88. .default(false),
  89. dateCreated: text("dateCreated").notNull(),
  90. serverAdmin: integer("serverAdmin", { mode: "boolean" })
  91. .notNull()
  92. .default(false)
  93. });
  94. export const newts = sqliteTable("newt", {
  95. newtId: text("id").primaryKey(),
  96. secretHash: text("secretHash").notNull(),
  97. dateCreated: text("dateCreated").notNull(),
  98. siteId: integer("siteId").references(() => sites.siteId, {
  99. onDelete: "cascade"
  100. })
  101. });
  102. export const twoFactorBackupCodes = sqliteTable("twoFactorBackupCodes", {
  103. codeId: integer("id").primaryKey({ autoIncrement: true }),
  104. userId: text("userId")
  105. .notNull()
  106. .references(() => users.userId, { onDelete: "cascade" }),
  107. codeHash: text("codeHash").notNull()
  108. });
  109. export const sessions = sqliteTable("session", {
  110. sessionId: text("id").primaryKey(),
  111. userId: text("userId")
  112. .notNull()
  113. .references(() => users.userId, { onDelete: "cascade" }),
  114. expiresAt: integer("expiresAt").notNull()
  115. });
  116. export const newtSessions = sqliteTable("newtSession", {
  117. sessionId: text("id").primaryKey(),
  118. newtId: text("newtId")
  119. .notNull()
  120. .references(() => newts.newtId, { onDelete: "cascade" }),
  121. expiresAt: integer("expiresAt").notNull()
  122. });
  123. export const userOrgs = sqliteTable("userOrgs", {
  124. userId: text("userId")
  125. .notNull()
  126. .references(() => users.userId, { onDelete: "cascade" }),
  127. orgId: text("orgId")
  128. .references(() => orgs.orgId, {
  129. onDelete: "cascade"
  130. })
  131. .notNull(),
  132. roleId: integer("roleId")
  133. .notNull()
  134. .references(() => roles.roleId),
  135. isOwner: integer("isOwner", { mode: "boolean" }).notNull().default(false)
  136. });
  137. export const emailVerificationCodes = sqliteTable("emailVerificationCodes", {
  138. codeId: integer("id").primaryKey({ autoIncrement: true }),
  139. userId: text("userId")
  140. .notNull()
  141. .references(() => users.userId, { onDelete: "cascade" }),
  142. email: text("email").notNull(),
  143. code: text("code").notNull(),
  144. expiresAt: integer("expiresAt").notNull()
  145. });
  146. export const passwordResetTokens = sqliteTable("passwordResetTokens", {
  147. tokenId: integer("id").primaryKey({ autoIncrement: true }),
  148. email: text("email").notNull(),
  149. userId: text("userId")
  150. .notNull()
  151. .references(() => users.userId, { onDelete: "cascade" }),
  152. tokenHash: text("tokenHash").notNull(),
  153. expiresAt: integer("expiresAt").notNull()
  154. });
  155. export const actions = sqliteTable("actions", {
  156. actionId: text("actionId").primaryKey(),
  157. name: text("name"),
  158. description: text("description")
  159. });
  160. export const roles = sqliteTable("roles", {
  161. roleId: integer("roleId").primaryKey({ autoIncrement: true }),
  162. orgId: text("orgId")
  163. .references(() => orgs.orgId, {
  164. onDelete: "cascade"
  165. })
  166. .notNull(),
  167. isAdmin: integer("isAdmin", { mode: "boolean" }),
  168. name: text("name").notNull(),
  169. description: text("description")
  170. });
  171. export const roleActions = sqliteTable("roleActions", {
  172. roleId: integer("roleId")
  173. .notNull()
  174. .references(() => roles.roleId, { onDelete: "cascade" }),
  175. actionId: text("actionId")
  176. .notNull()
  177. .references(() => actions.actionId, { onDelete: "cascade" }),
  178. orgId: text("orgId")
  179. .notNull()
  180. .references(() => orgs.orgId, { onDelete: "cascade" })
  181. });
  182. export const userActions = sqliteTable("userActions", {
  183. userId: text("userId")
  184. .notNull()
  185. .references(() => users.userId, { onDelete: "cascade" }),
  186. actionId: text("actionId")
  187. .notNull()
  188. .references(() => actions.actionId, { onDelete: "cascade" }),
  189. orgId: text("orgId")
  190. .notNull()
  191. .references(() => orgs.orgId, { onDelete: "cascade" })
  192. });
  193. export const roleSites = sqliteTable("roleSites", {
  194. roleId: integer("roleId")
  195. .notNull()
  196. .references(() => roles.roleId, { onDelete: "cascade" }),
  197. siteId: integer("siteId")
  198. .notNull()
  199. .references(() => sites.siteId, { onDelete: "cascade" })
  200. });
  201. export const userSites = sqliteTable("userSites", {
  202. userId: text("userId")
  203. .notNull()
  204. .references(() => users.userId, { onDelete: "cascade" }),
  205. siteId: integer("siteId")
  206. .notNull()
  207. .references(() => sites.siteId, { onDelete: "cascade" })
  208. });
  209. export const roleResources = sqliteTable("roleResources", {
  210. roleId: integer("roleId")
  211. .notNull()
  212. .references(() => roles.roleId, { onDelete: "cascade" }),
  213. resourceId: integer("resourceId")
  214. .notNull()
  215. .references(() => resources.resourceId, { onDelete: "cascade" })
  216. });
  217. export const userResources = sqliteTable("userResources", {
  218. userId: text("userId")
  219. .notNull()
  220. .references(() => users.userId, { onDelete: "cascade" }),
  221. resourceId: integer("resourceId")
  222. .notNull()
  223. .references(() => resources.resourceId, { onDelete: "cascade" })
  224. });
  225. export const limitsTable = sqliteTable("limits", {
  226. limitId: integer("limitId").primaryKey({ autoIncrement: true }),
  227. orgId: text("orgId")
  228. .references(() => orgs.orgId, {
  229. onDelete: "cascade"
  230. })
  231. .notNull(),
  232. name: text("name").notNull(),
  233. value: integer("value").notNull(),
  234. description: text("description")
  235. });
  236. export const userInvites = sqliteTable("userInvites", {
  237. inviteId: text("inviteId").primaryKey(),
  238. orgId: text("orgId")
  239. .notNull()
  240. .references(() => orgs.orgId, { onDelete: "cascade" }),
  241. email: text("email").notNull(),
  242. expiresAt: integer("expiresAt").notNull(),
  243. tokenHash: text("token").notNull(),
  244. roleId: integer("roleId")
  245. .notNull()
  246. .references(() => roles.roleId, { onDelete: "cascade" })
  247. });
  248. export const resourcePincode = sqliteTable("resourcePincode", {
  249. pincodeId: integer("pincodeId").primaryKey({
  250. autoIncrement: true
  251. }),
  252. resourceId: integer("resourceId")
  253. .notNull()
  254. .references(() => resources.resourceId, { onDelete: "cascade" }),
  255. pincodeHash: text("pincodeHash").notNull(),
  256. digitLength: integer("digitLength").notNull()
  257. });
  258. export const resourcePassword = sqliteTable("resourcePassword", {
  259. passwordId: integer("passwordId").primaryKey({
  260. autoIncrement: true
  261. }),
  262. resourceId: integer("resourceId")
  263. .notNull()
  264. .references(() => resources.resourceId, { onDelete: "cascade" }),
  265. passwordHash: text("passwordHash").notNull()
  266. });
  267. export const resourceAccessToken = sqliteTable("resourceAccessToken", {
  268. accessTokenId: text("accessTokenId").primaryKey(),
  269. orgId: text("orgId")
  270. .notNull()
  271. .references(() => orgs.orgId, { onDelete: "cascade" }),
  272. resourceId: integer("resourceId")
  273. .notNull()
  274. .references(() => resources.resourceId, { onDelete: "cascade" }),
  275. tokenHash: text("tokenHash").notNull(),
  276. sessionLength: integer("sessionLength").notNull(),
  277. expiresAt: integer("expiresAt"),
  278. title: text("title"),
  279. description: text("description"),
  280. createdAt: integer("createdAt").notNull()
  281. });
  282. export const resourceSessions = sqliteTable("resourceSessions", {
  283. sessionId: text("id").primaryKey(),
  284. resourceId: integer("resourceId")
  285. .notNull()
  286. .references(() => resources.resourceId, { onDelete: "cascade" }),
  287. expiresAt: integer("expiresAt").notNull(),
  288. sessionLength: integer("sessionLength").notNull(),
  289. doNotExtend: integer("doNotExtend", { mode: "boolean" })
  290. .notNull()
  291. .default(false),
  292. isRequestToken: integer("isRequestToken", { mode: "boolean" }),
  293. userSessionId: text("userSessionId").references(() => sessions.sessionId, {
  294. onDelete: "cascade"
  295. }),
  296. passwordId: integer("passwordId").references(
  297. () => resourcePassword.passwordId,
  298. {
  299. onDelete: "cascade"
  300. }
  301. ),
  302. pincodeId: integer("pincodeId").references(
  303. () => resourcePincode.pincodeId,
  304. {
  305. onDelete: "cascade"
  306. }
  307. ),
  308. whitelistId: integer("whitelistId").references(
  309. () => resourceWhitelist.whitelistId,
  310. {
  311. onDelete: "cascade"
  312. }
  313. ),
  314. accessTokenId: text("accessTokenId").references(
  315. () => resourceAccessToken.accessTokenId,
  316. {
  317. onDelete: "cascade"
  318. }
  319. )
  320. });
  321. export const resourceWhitelist = sqliteTable("resourceWhitelist", {
  322. whitelistId: integer("id").primaryKey({ autoIncrement: true }),
  323. email: text("email").notNull(),
  324. resourceId: integer("resourceId")
  325. .notNull()
  326. .references(() => resources.resourceId, { onDelete: "cascade" })
  327. });
  328. export const resourceOtp = sqliteTable("resourceOtp", {
  329. otpId: integer("otpId").primaryKey({
  330. autoIncrement: true
  331. }),
  332. resourceId: integer("resourceId")
  333. .notNull()
  334. .references(() => resources.resourceId, { onDelete: "cascade" }),
  335. email: text("email").notNull(),
  336. otpHash: text("otpHash").notNull(),
  337. expiresAt: integer("expiresAt").notNull()
  338. });
  339. export const versionMigrations = sqliteTable("versionMigrations", {
  340. version: text("version").primaryKey(),
  341. executedAt: integer("executedAt").notNull()
  342. });
  343. export type Org = InferSelectModel<typeof orgs>;
  344. export type User = InferSelectModel<typeof users>;
  345. export type Site = InferSelectModel<typeof sites>;
  346. export type Resource = InferSelectModel<typeof resources>;
  347. export type ExitNode = InferSelectModel<typeof exitNodes>;
  348. export type Target = InferSelectModel<typeof targets>;
  349. export type Session = InferSelectModel<typeof sessions>;
  350. export type Newt = InferSelectModel<typeof newts>;
  351. export type NewtSession = InferSelectModel<typeof newtSessions>;
  352. export type EmailVerificationCode = InferSelectModel<
  353. typeof emailVerificationCodes
  354. >;
  355. export type TwoFactorBackupCode = InferSelectModel<typeof twoFactorBackupCodes>;
  356. export type PasswordResetToken = InferSelectModel<typeof passwordResetTokens>;
  357. export type Role = InferSelectModel<typeof roles>;
  358. export type Action = InferSelectModel<typeof actions>;
  359. export type RoleAction = InferSelectModel<typeof roleActions>;
  360. export type UserAction = InferSelectModel<typeof userActions>;
  361. export type RoleSite = InferSelectModel<typeof roleSites>;
  362. export type UserSite = InferSelectModel<typeof userSites>;
  363. export type RoleResource = InferSelectModel<typeof roleResources>;
  364. export type UserResource = InferSelectModel<typeof userResources>;
  365. export type Limit = InferSelectModel<typeof limitsTable>;
  366. export type UserInvite = InferSelectModel<typeof userInvites>;
  367. export type UserOrg = InferSelectModel<typeof userOrgs>;
  368. export type ResourceSession = InferSelectModel<typeof resourceSessions>;
  369. export type ResourcePincode = InferSelectModel<typeof resourcePincode>;
  370. export type ResourcePassword = InferSelectModel<typeof resourcePassword>;
  371. export type ResourceOtp = InferSelectModel<typeof resourceOtp>;
  372. export type ResourceAccessToken = InferSelectModel<typeof resourceAccessToken>;
  373. export type ResourceWhitelist = InferSelectModel<typeof resourceWhitelist>;
  374. export type VersionMigration = InferSelectModel<typeof versionMigrations>;