schema.ts 14 KB

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