schema.ts 15 KB

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