@raketa-cloud/admin 0.0.98 → 0.0.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raketa-cloud/admin",
3
- "version": "0.0.98",
3
+ "version": "0.0.100",
4
4
  "main": "src/index.js",
5
5
  "scripts": {
6
6
  "dev": "npx tailwindcss -i ./src/styles/application.css -o ../../apps/admin/static/application.css --watch",
package/src/Adapter.js CHANGED
@@ -10,6 +10,7 @@ import form_for from "./helpers/form_for";
10
10
  import history from "./helpers/historyUtils";
11
11
  import pagination from "./helpers/pagination_helper";
12
12
  import sort_button from "./helpers/sort_button";
13
+ import utils from "./helpers/utils";
13
14
 
14
15
  function escapeHtml(string) {
15
16
  var matchHtmlRegExp = /["'&<>]/;
@@ -172,6 +173,7 @@ export default class Adapter {
172
173
  f,
173
174
  form_for: form_for(viewHelpersConfig),
174
175
  history,
176
+ utils,
175
177
  sort_button,
176
178
  pagination,
177
179
  Inflector,
package/src/cipher.js ADDED
@@ -0,0 +1,49 @@
1
+ import {
2
+ pbkdf2Sync,
3
+ createCipheriv,
4
+ createDecipheriv,
5
+ randomBytes,
6
+ } from "node:crypto";
7
+
8
+ const ALGORITHM = "aes-256-cbc";
9
+ const IV = randomBytes(16);
10
+ const SALT = "some string to have a salt value..";
11
+
12
+ function deriveKey(password) {
13
+ return pbkdf2Sync(password, SALT, 100000, 32, "sha256");
14
+ }
15
+
16
+ function encrypt(plaintext, config) {
17
+ const cipher = createCipheriv(
18
+ ALGORITHM,
19
+ deriveKey(config.secrets.crypto_secret),
20
+ IV
21
+ );
22
+
23
+ let encrypted = cipher.update(plaintext, "utf8", "hex");
24
+
25
+ encrypted += cipher.final("hex");
26
+
27
+ return `${IV.toString("hex")}:${encrypted}`;
28
+ }
29
+
30
+ function decrypt(encryptedText, config) {
31
+ const [ivHex, encrypted] = encryptedText.split(":");
32
+ const iv = Buffer.from(ivHex, "hex");
33
+
34
+ const decipher = createDecipheriv(
35
+ ALGORITHM,
36
+ deriveKey(config.secrets.crypto_secret),
37
+ iv
38
+ );
39
+
40
+ let decrypted = decipher.update(encrypted, "hex", "utf8");
41
+ decrypted += decipher.final("utf8");
42
+
43
+ return decrypted;
44
+ }
45
+
46
+ export default {
47
+ encrypt,
48
+ decrypt,
49
+ };
@@ -6,17 +6,11 @@ import {
6
6
 
7
7
  export default class Settings extends RaketaClient {
8
8
  async find(locale) {
9
- const {
10
- setting,
11
- } = await this.query(SettingDocument, {
9
+ const { setting } = await this.query(SettingDocument, {
12
10
  locale,
13
11
  });
14
12
 
15
- if (!setting?.value) {
16
- this.logError(`Cannot find settings for ${locale} locale.`)
17
- }
18
-
19
- return setting.value;
13
+ return setting?.value || {};
20
14
  }
21
15
 
22
16
  async update(locale, params) {
@@ -0,0 +1,21 @@
1
+ function includedInCollection(value, collection) {
2
+ if (!collection) {
3
+ return false;
4
+ }
5
+
6
+ if (typeof collection === "string") {
7
+ return value === collection;
8
+ }
9
+
10
+ if (Array.isArray(collection)) {
11
+ return collection.includes(value);
12
+ }
13
+
14
+ throw new Error(
15
+ "Invalid input for collection. Expected a string or an array."
16
+ );
17
+ }
18
+
19
+ export default {
20
+ includedInCollection,
21
+ };
@@ -1,45 +1,30 @@
1
- import { createHmac, randomBytes } from "node:crypto";
2
1
  import ejs from "ejs";
3
2
  import { deleteCookie, getCookie, setCookie } from "hono/cookie";
4
3
  import currentPath from "./currentPath.cjs";
5
4
  import AuthHelper from "./helpers/AuthHelper";
6
- // TODO: Maybe change the encryption mechanism?
7
- import simpleCipher from "./simpleCipher";
5
+ import cipher from "./cipher";
8
6
 
9
- // Generate a random signing secret on every server restart
10
- // const SIGNING_SECRET = randomBytes(64).toString("hex");
11
7
  const DELIMITER = ",";
12
8
 
13
- function calculateHash(text, config) {
14
- return createHmac("sha256", config.secrets.signing_secret)
15
- .update(text)
16
- .digest("hex");
17
- }
18
-
19
9
  function obfuscateToken(token, config) {
20
10
  const date = new Date();
21
11
  const timestamp = date.getTime() + 2 * 60000;
22
- const timestamped = [token, timestamp].join(DELIMITER);
23
- const hash = calculateHash(timestamped, config);
24
- const signed = [hash, timestamped].join(DELIMITER);
12
+ const data = [token, timestamp].join(DELIMITER);
25
13
 
26
- return Buffer.from(simpleCipher.encrypt(signed, config)).toString("base64");
14
+ return Buffer.from(cipher.encrypt(data, config)).toString("base64");
27
15
  }
28
16
 
29
17
  function extractToken(text, config) {
30
18
  const encrypted = Buffer.from(text, "base64").toString("ascii");
31
- const signed = simpleCipher.decrypt(encrypted, config);
32
- const [hash, token, timestamp] = signed.split(DELIMITER);
19
+ const data = cipher.decrypt(encrypted, config);
20
+ const [token, timestamp] = data.split(DELIMITER);
21
+
33
22
  const tDate = new Date(Number.parseInt(timestamp, 10));
34
23
 
35
24
  if (tDate < new Date()) {
36
25
  return null;
37
26
  }
38
27
 
39
- if (hash !== calculateHash([token, timestamp].join(DELIMITER), config)) {
40
- return null;
41
- }
42
-
43
28
  return token;
44
29
  }
45
30
 
@@ -0,0 +1,27 @@
1
+ import utils from "../../helpers/utils";
2
+
3
+ describe("includedInCollection", () => {
4
+ it("returns true when the given collection is a string equal to the given value", () => {
5
+ expect(utils.includedInCollection("key", "key")).toEqual(true);
6
+ });
7
+
8
+ it("returns false when the given collection is a string not equal to the given value", () => {
9
+ expect(utils.includedInCollection("key", "key-2")).toEqual(false);
10
+ });
11
+
12
+ it("returns true when the given collection is an array including the given value", () => {
13
+ expect(utils.includedInCollection("key", ["key"])).toEqual(true);
14
+ });
15
+
16
+ it("returns false when the given collection is an array not including the given value", () => {
17
+ expect(utils.includedInCollection("key", ["key-2"])).toEqual(false);
18
+ });
19
+
20
+ it("returns false when the given collection null", () => {
21
+ expect(utils.includedInCollection("key", null)).toEqual(false);
22
+ });
23
+
24
+ it("returns false when the given collection undefined", () => {
25
+ expect(utils.includedInCollection("key", undefined)).toEqual(false);
26
+ });
27
+ });
@@ -58,7 +58,7 @@
58
58
  <div class="checkbox-group mb-4">
59
59
  <% Object.entries(history.changeTypes(_context.resourceConfig.articleType)).forEach(([key, {label}])=> { %>
60
60
  <div class="flex items-center gap-1">
61
- <% if (Array.from(_context.query["f:change_type"] || []).includes(key)) { %>
61
+ <% if (utils.includedInCollection(key, _context.query["f:change_type"])) { %>
62
62
  <input type="checkbox" name="f:change_type" id='change-<%= key %>' checked value="<%= key %>" class="hover:cursor-pointer">
63
63
  <% } else { %>
64
64
  <input type="checkbox" name="f:change_type" id='change-<%= key %>' value="<%= key %>" class="hover:cursor-pointer">
@@ -144,7 +144,7 @@
144
144
  <div class="checkbox-group mb-4">
145
145
  <% tags.forEach((item,idx)=> { %>
146
146
  <div class="flex items-center gap-1">
147
- <% if (Array.from(_context.query["f:tags"] || []).includes(item.id)) { %>
147
+ <% if (utils.includedInCollection(item.id, _context.query["f:tags"])) { %>
148
148
  <input type="checkbox" name="f:tags" id='tag-<%= item.id %>' checked value="<%= item.id %>" class="hover:cursor-pointer">
149
149
  <% } else { %>
150
150
  <input type="checkbox" name="f:tags" id='tag-<%= item.id %>' value="<%= item.id %>" class="hover:cursor-pointer">
@@ -58,7 +58,7 @@
58
58
  <div class="checkbox-group mb-4">
59
59
  <% Object.entries(history.changeTypes(_context.resourceConfig.eventType)).forEach(([key, {label}])=> { %>
60
60
  <div class="flex items-center gap-1">
61
- <% if (Array.from(_context.query["f:change_type"] || []).includes(key)) { %>
61
+ <% if (utils.includedInCollection(key, _context.query["f:change_type"])) { %>
62
62
  <input type="checkbox" name="f:change_type" id='change-<%= key %>' checked value="<%= key %>" class="hover:cursor-pointer">
63
63
  <% } else { %>
64
64
  <input type="checkbox" name="f:change_type" id='change-<%= key %>' value="<%= key %>" class="hover:cursor-pointer">
@@ -144,7 +144,7 @@
144
144
  <div class="checkbox-group mb-4">
145
145
  <% tags.forEach((item,idx)=> { %>
146
146
  <div class="flex items-center gap-1">
147
- <% if (Array.from(_context.query["f:tags"] || []).includes(item.id)) { %>
147
+ <% if (utils.includedInCollection(item.id, _context.query["f:tags"])) { %>
148
148
  <input type="checkbox" name="f:tags" id='tag-<%= item.id %>' checked value="<%= item.id %>" class="hover:cursor-pointer">
149
149
  <% } else { %>
150
150
  <input type="checkbox" name="f:tags" id='tag-<%= item.id %>' value="<%= item.id %>" class="hover:cursor-pointer">
@@ -58,7 +58,7 @@
58
58
  <div class="checkbox-group mb-4">
59
59
  <% Object.entries(history.changeTypes(_context.resourceConfig.pageType)).forEach(([key, {label}])=> { %>
60
60
  <div class="flex items-center gap-1">
61
- <% if (Array.from(_context.query["f:change_type"] || []).includes(key)) { %>
61
+ <% if (utils.includedInCollection(key, _context.query["f:change_type"])) { %>
62
62
  <input type="checkbox" name="f:change_type" id='change-<%= key %>' checked value="<%= key %>" class="hover:cursor-pointer">
63
63
  <% } else { %>
64
64
  <input type="checkbox" name="f:change_type" id='change-<%= key %>' value="<%= key %>" class="hover:cursor-pointer">
@@ -139,7 +139,7 @@
139
139
  <div class="checkbox-group mb-4">
140
140
  <% tags.forEach((item,idx)=> { %>
141
141
  <div class="flex items-center gap-1">
142
- <% if (Array.from(_context.query["f:tags"] || []).includes(item.id)) { %>
142
+ <% if (utils.includedInCollection(item.id, _context.query["f:tags"])) { %>
143
143
  <input type="checkbox" name="f:tags" id='tag-<%= item.id %>' checked value="<%= item.id %>" class="hover:cursor-pointer">
144
144
  <% } else { %>
145
145
  <input type="checkbox" name="f:tags" id='tag-<%= item.id %>' value="<%= item.id %>" class="hover:cursor-pointer">
@@ -1,58 +0,0 @@
1
- const ALPHABET =
2
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.";
3
-
4
- function generateEncryptionLookup(key) {
5
- const lookup = {};
6
-
7
- ALPHABET.split("").forEach((char, index) => {
8
- lookup[char] = key[index];
9
- });
10
-
11
- return lookup;
12
- }
13
-
14
- function generateDecryptionLookup(key) {
15
- const lookup = {};
16
-
17
- key.split("").forEach((char, index) => {
18
- lookup[char] = ALPHABET[index];
19
- });
20
-
21
- return lookup;
22
- }
23
-
24
- // function generateKey() {
25
- // const shuffled = ALPHABET.split("")
26
- // .sort(() => Math.random() - 0.5)
27
- // .join("");
28
-
29
- // return shuffled;
30
- // }
31
-
32
- // Scramble lookup maps on every server restart
33
- // const CIPHER_KEY = generateKey();
34
- // const ENCRYPT_LOOKUP = generateEncryptionLookup(CIPHER_KEY);
35
- // const DECRYPT_LOOKUP = generateDecryptionLookup(CIPHER_KEY);
36
-
37
- function encrypt(plaintext, config) {
38
- const ecryptLookup = generateEncryptionLookup(config.secrets.crypto_secret);
39
-
40
- return plaintext
41
- .split("")
42
- .map((char) => ecryptLookup[char] || char)
43
- .join("");
44
- }
45
-
46
- function decrypt(ciphertext, config) {
47
- const decryptLookup = generateDecryptionLookup(config.secrets.crypto_secret);
48
-
49
- return ciphertext
50
- .split("")
51
- .map((char) => decryptLookup[char] || char)
52
- .join("");
53
- }
54
-
55
- export default {
56
- encrypt,
57
- decrypt,
58
- };