key.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import { z } from "zod"
  2. import { fn } from "./util/fn"
  3. import { Actor } from "./actor"
  4. import { and, Database, eq, isNull, sql } from "./drizzle"
  5. import { Identifier } from "./identifier"
  6. import { KeyTable } from "./schema/key.sql"
  7. import { UserTable } from "./schema/user.sql"
  8. import { AuthTable } from "./schema/auth.sql"
  9. export namespace Key {
  10. export const list = fn(z.void(), async () => {
  11. const keys = await Database.use((tx) =>
  12. tx
  13. .select({
  14. id: KeyTable.id,
  15. name: KeyTable.name,
  16. key: KeyTable.key,
  17. timeUsed: KeyTable.timeUsed,
  18. userID: KeyTable.userID,
  19. email: AuthTable.subject,
  20. })
  21. .from(KeyTable)
  22. .innerJoin(UserTable, and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID)))
  23. .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")))
  24. .where(
  25. and(
  26. ...[
  27. eq(KeyTable.workspaceID, Actor.workspace()),
  28. isNull(KeyTable.timeDeleted),
  29. ...(Actor.userRole() === "admin" ? [] : [eq(KeyTable.userID, Actor.userID())]),
  30. ],
  31. ),
  32. )
  33. .orderBy(sql`${KeyTable.name} DESC`),
  34. )
  35. // only return value for user's keys
  36. return keys.map((key) => ({
  37. ...key,
  38. key: key.userID === Actor.userID() ? key.key : undefined,
  39. keyDisplay: `${key.key.slice(0, 7)}...${key.key.slice(-4)}`,
  40. }))
  41. })
  42. export const create = fn(
  43. z.object({
  44. userID: z.string(),
  45. name: z.string().min(1).max(255),
  46. }),
  47. async (input) => {
  48. const { name } = input
  49. // Generate secret key: sk- + 64 random characters (upper, lower, numbers)
  50. const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
  51. let secretKey = "sk-"
  52. const array = new Uint32Array(64)
  53. crypto.getRandomValues(array)
  54. for (let i = 0, l = array.length; i < l; i++) {
  55. secretKey += chars[array[i] % chars.length]
  56. }
  57. const keyID = Identifier.create("key")
  58. await Database.use((tx) =>
  59. tx.insert(KeyTable).values({
  60. id: keyID,
  61. workspaceID: Actor.workspace(),
  62. userID: input.userID,
  63. name,
  64. key: secretKey,
  65. timeUsed: null,
  66. }),
  67. )
  68. return keyID
  69. },
  70. )
  71. export const remove = fn(z.object({ id: z.string() }), async (input) => {
  72. // only admin can remove other user's keys
  73. await Database.use((tx) =>
  74. tx
  75. .update(KeyTable)
  76. .set({
  77. timeDeleted: sql`now()`,
  78. })
  79. .where(
  80. and(
  81. ...[
  82. eq(KeyTable.id, input.id),
  83. eq(KeyTable.workspaceID, Actor.workspace()),
  84. ...(Actor.userRole() === "admin" ? [] : [eq(KeyTable.userID, Actor.userID())]),
  85. ],
  86. ),
  87. ),
  88. )
  89. })
  90. }