schema.ts 14 KB

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