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.

112 lines
2.6 KiB

11 months ago
  1. process.env.NODE_ENV === "development"
  2. ? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
  3. : require("dotenv").config();
  4. const JWT = require("jsonwebtoken");
  5. const { User } = require("../../models/user");
  6. const { jsonrepair } = require("jsonrepair");
  7. const extract = require("extract-json-from-string");
  8. function reqBody(request) {
  9. return typeof request.body === "string"
  10. ? JSON.parse(request.body)
  11. : request.body;
  12. }
  13. function queryParams(request) {
  14. return request.query;
  15. }
  16. function makeJWT(info = {}, expiry = "30d") {
  17. if (!process.env.JWT_SECRET)
  18. throw new Error("Cannot create JWT as JWT_SECRET is unset.");
  19. return JWT.sign(info, process.env.JWT_SECRET, { expiresIn: expiry });
  20. }
  21. // Note: Only valid for finding users in multi-user mode
  22. // as single-user mode with password is not a "user"
  23. async function userFromSession(request, response = null) {
  24. if (!!response && !!response.locals?.user) {
  25. return response.locals.user;
  26. }
  27. const auth = request.header("Authorization");
  28. const token = auth ? auth.split(" ")[1] : null;
  29. if (!token) {
  30. return null;
  31. }
  32. const valid = decodeJWT(token);
  33. if (!valid || !valid.id) {
  34. return null;
  35. }
  36. const user = await User.get({ id: valid.id });
  37. return user;
  38. }
  39. function decodeJWT(jwtToken) {
  40. try {
  41. return JWT.verify(jwtToken, process.env.JWT_SECRET);
  42. } catch {}
  43. return { p: null, id: null, username: null };
  44. }
  45. function multiUserMode(response) {
  46. return response?.locals?.multiUserMode;
  47. }
  48. function parseAuthHeader(headerValue = null, apiKey = null) {
  49. if (headerValue === null || apiKey === null) return {};
  50. if (headerValue === "Authorization")
  51. return { Authorization: `Bearer ${apiKey}` };
  52. return { [headerValue]: apiKey };
  53. }
  54. function safeJsonParse(jsonString, fallback = null) {
  55. if (jsonString === null) return fallback;
  56. try {
  57. return JSON.parse(jsonString);
  58. } catch {}
  59. if (jsonString?.startsWith("[") || jsonString?.startsWith("{")) {
  60. try {
  61. const repairedJson = jsonrepair(jsonString);
  62. return JSON.parse(repairedJson);
  63. } catch {}
  64. }
  65. try {
  66. return extract(jsonString)?.[0] || fallback;
  67. } catch {}
  68. return fallback;
  69. }
  70. function isValidUrl(urlString = "") {
  71. try {
  72. const url = new URL(urlString);
  73. if (!["http:", "https:"].includes(url.protocol)) return false;
  74. return true;
  75. } catch (e) {}
  76. return false;
  77. }
  78. function toValidNumber(number = null, fallback = null) {
  79. if (isNaN(Number(number))) return fallback;
  80. return Number(number);
  81. }
  82. module.exports = {
  83. reqBody,
  84. multiUserMode,
  85. queryParams,
  86. makeJWT,
  87. decodeJWT,
  88. userFromSession,
  89. parseAuthHeader,
  90. safeJsonParse,
  91. isValidUrl,
  92. toValidNumber,
  93. };