You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.9 KiB

11 months ago
  1. const prisma = require("../utils/prisma");
  2. const { SystemSettings } = require("./systemSettings");
  3. const { ROLES } = require("../utils/middleware/multiUserProtected");
  4. const BrowserExtensionApiKey = {
  5. /**
  6. * Creates a new secret for a browser extension API key.
  7. * @returns {string} brx-*** API key to use with extension
  8. */
  9. makeSecret: () => {
  10. const uuidAPIKey = require("uuid-apikey");
  11. return `brx-${uuidAPIKey.create().apiKey}`;
  12. },
  13. /**
  14. * Creates a new api key for the browser Extension
  15. * @param {number|null} userId - User id to associate creation of key with.
  16. * @returns {Promise<{apiKey: import("@prisma/client").browser_extension_api_keys|null, error:string|null}>}
  17. */
  18. create: async function (userId = null) {
  19. try {
  20. const apiKey = await prisma.browser_extension_api_keys.create({
  21. data: {
  22. key: this.makeSecret(),
  23. user_id: userId,
  24. },
  25. });
  26. return { apiKey, error: null };
  27. } catch (error) {
  28. console.error("Failed to create browser extension API key", error);
  29. return { apiKey: null, error: error.message };
  30. }
  31. },
  32. /**
  33. * Validated existing API key
  34. * @param {string} key
  35. * @returns {Promise<{apiKey: import("@prisma/client").browser_extension_api_keys|boolean}>}
  36. */
  37. validate: async function (key) {
  38. if (!key.startsWith("brx-")) return false;
  39. const apiKey = await prisma.browser_extension_api_keys.findUnique({
  40. where: { key: key.toString() },
  41. include: { user: true },
  42. });
  43. if (!apiKey) return false;
  44. const multiUserMode = await SystemSettings.isMultiUserMode();
  45. if (!multiUserMode) return apiKey; // In single-user mode, all keys are valid
  46. // In multi-user mode, check if the key is associated with a user
  47. return apiKey.user_id ? apiKey : false;
  48. },
  49. /**
  50. * Fetches browser api key by params.
  51. * @param {object} clause - Prisma props for search
  52. * @returns {Promise<{apiKey: import("@prisma/client").browser_extension_api_keys|boolean}>}
  53. */
  54. get: async function (clause = {}) {
  55. try {
  56. const apiKey = await prisma.browser_extension_api_keys.findFirst({
  57. where: clause,
  58. });
  59. return apiKey;
  60. } catch (error) {
  61. console.error("FAILED TO GET BROWSER EXTENSION API KEY.", error.message);
  62. return null;
  63. }
  64. },
  65. /**
  66. * Deletes browser api key by db id.
  67. * @param {number} id - database id of browser key
  68. * @returns {Promise<{success: boolean, error:string|null}>}
  69. */
  70. delete: async function (id) {
  71. try {
  72. await prisma.browser_extension_api_keys.delete({
  73. where: { id: parseInt(id) },
  74. });
  75. return { success: true, error: null };
  76. } catch (error) {
  77. console.error("Failed to delete browser extension API key", error);
  78. return { success: false, error: error.message };
  79. }
  80. },
  81. /**
  82. * Gets browser keys by params
  83. * @param {object} clause
  84. * @param {number|null} limit
  85. * @param {object|null} orderBy
  86. * @returns {Promise<import("@prisma/client").browser_extension_api_keys[]>}
  87. */
  88. where: async function (clause = {}, limit = null, orderBy = null) {
  89. try {
  90. const apiKeys = await prisma.browser_extension_api_keys.findMany({
  91. where: clause,
  92. ...(limit !== null ? { take: limit } : {}),
  93. ...(orderBy !== null ? { orderBy } : {}),
  94. include: { user: true },
  95. });
  96. return apiKeys;
  97. } catch (error) {
  98. console.error("FAILED TO GET BROWSER EXTENSION API KEYS.", error.message);
  99. return [];
  100. }
  101. },
  102. /**
  103. * Get browser API keys for user
  104. * @param {import("@prisma/client").users} user
  105. * @param {object} clause
  106. * @param {number|null} limit
  107. * @param {object|null} orderBy
  108. * @returns {Promise<import("@prisma/client").browser_extension_api_keys[]>}
  109. */
  110. whereWithUser: async function (
  111. user,
  112. clause = {},
  113. limit = null,
  114. orderBy = null
  115. ) {
  116. // Admin can view and use any keys
  117. if ([ROLES.admin].includes(user.role))
  118. return await this.where(clause, limit, orderBy);
  119. try {
  120. const apiKeys = await prisma.browser_extension_api_keys.findMany({
  121. where: {
  122. ...clause,
  123. user_id: user.id,
  124. },
  125. include: { user: true },
  126. ...(limit !== null ? { take: limit } : {}),
  127. ...(orderBy !== null ? { orderBy } : {}),
  128. });
  129. return apiKeys;
  130. } catch (error) {
  131. console.error(error.message);
  132. return [];
  133. }
  134. },
  135. /**
  136. * Updates owner of all DB ids to new admin.
  137. * @param {number} userId
  138. * @returns {Promise<void>}
  139. */
  140. migrateApiKeysToMultiUser: async function (userId) {
  141. try {
  142. await prisma.browser_extension_api_keys.updateMany({
  143. where: {
  144. user_id: null,
  145. },
  146. data: {
  147. user_id: userId,
  148. },
  149. });
  150. console.log("Successfully migrated API keys to multi-user mode");
  151. } catch (error) {
  152. console.error("Error migrating API keys to multi-user mode:", error);
  153. }
  154. },
  155. };
  156. module.exports = { BrowserExtensionApiKey };