@oondemand/oon-core-back 0.6.7 → 0.6.8

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": "@oondemand/oon-core-back",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/oondemand/oon-platform.git",
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+
3
+ const crypto = require("node:crypto");
4
+
5
+ const APP_CODE_MAX_LENGTH = 24;
6
+ const APP_CODE_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,22}[a-z0-9])?$/;
7
+ const INSTANCE_UID_ALPHABET = "23456789abcdefghjkmnopqrstuvwxyz";
8
+ const INSTANCE_UID_LENGTH = 16;
9
+ const INSTANCE_UID_BYTES = 10;
10
+ const INSTANCE_UID_PATTERN = /^[23456789abcdefghjkmnopqrstuvwxyz]{16}$/;
11
+
12
+ const ENVIRONMENT_TOKENS = Object.freeze({
13
+ desenvolvimento: "dev",
14
+ homologacao: "hml",
15
+ producao: "prod",
16
+ dev: "dev",
17
+ hml: "hml",
18
+ prod: "prod",
19
+ });
20
+
21
+ class TechnicalIdentityError extends Error {
22
+ constructor(message, code, details = {}) {
23
+ super(message);
24
+ this.name = "TechnicalIdentityError";
25
+ this.code = code;
26
+ this.details = details;
27
+ }
28
+ }
29
+
30
+ function assertAppCode(value) {
31
+ const appCode = typeof value === "string" ? value : "";
32
+ if (!APP_CODE_PATTERN.test(appCode)) {
33
+ throw new TechnicalIdentityError(
34
+ `appCode deve seguir ${APP_CODE_PATTERN} e possuir no máximo ${APP_CODE_MAX_LENGTH} caracteres ASCII.`,
35
+ "TECHNICAL_APP_CODE_INVALID",
36
+ { appCode },
37
+ );
38
+ }
39
+ return appCode;
40
+ }
41
+
42
+ function assertInstanceUid(value) {
43
+ const instanceUid = typeof value === "string" ? value : "";
44
+ if (!INSTANCE_UID_PATTERN.test(instanceUid)) {
45
+ throw new TechnicalIdentityError(
46
+ `instanceUid deve possuir ${INSTANCE_UID_LENGTH} caracteres no alfabeto canônico.`,
47
+ "TECHNICAL_INSTANCE_UID_INVALID",
48
+ { instanceUid },
49
+ );
50
+ }
51
+ return instanceUid;
52
+ }
53
+
54
+ function environmentToken(value) {
55
+ const environment = String(value || "").trim().toLowerCase();
56
+ const hasEnvironment = Object.prototype.hasOwnProperty.call(ENVIRONMENT_TOKENS, environment);
57
+ const token = hasEnvironment ? ENVIRONMENT_TOKENS[environment] : null;
58
+ if (!token) {
59
+ throw new TechnicalIdentityError(
60
+ "Ambiente técnico inválido.",
61
+ "TECHNICAL_ENVIRONMENT_INVALID",
62
+ { environment },
63
+ );
64
+ }
65
+ return token;
66
+ }
67
+
68
+ function encodeInstanceUid(bytes) {
69
+ const buffer = Buffer.from(bytes || []);
70
+ if (buffer.length !== INSTANCE_UID_BYTES) {
71
+ throw new TechnicalIdentityError(
72
+ `instanceUid exige exatamente ${INSTANCE_UID_BYTES} bytes aleatórios.`,
73
+ "TECHNICAL_INSTANCE_UID_RANDOM_BYTES_INVALID",
74
+ { receivedBytes: buffer.length },
75
+ );
76
+ }
77
+
78
+ let accumulator = 0;
79
+ let bits = 0;
80
+ let output = "";
81
+ for (const byte of buffer) {
82
+ accumulator = (accumulator << 8) | byte;
83
+ bits += 8;
84
+ while (bits >= 5) {
85
+ bits -= 5;
86
+ output += INSTANCE_UID_ALPHABET[(accumulator >> bits) & 31];
87
+ accumulator &= (1 << bits) - 1;
88
+ }
89
+ }
90
+
91
+ if (bits !== 0 || output.length !== INSTANCE_UID_LENGTH) {
92
+ throw new TechnicalIdentityError(
93
+ "Falha ao codificar instanceUid de 80 bits.",
94
+ "TECHNICAL_INSTANCE_UID_ENCODING_INVALID",
95
+ );
96
+ }
97
+ return output;
98
+ }
99
+
100
+ function generateInstanceUid(randomBytes = crypto.randomBytes) {
101
+ if (typeof randomBytes !== "function") {
102
+ throw new TypeError("randomBytes deve ser uma função.");
103
+ }
104
+ return encodeInstanceUid(randomBytes(INSTANCE_UID_BYTES));
105
+ }
106
+
107
+ function technicalIdentity({ appCode, instanceUid, environment }) {
108
+ const canonicalAppCode = assertAppCode(appCode);
109
+ const canonicalInstanceUid = assertInstanceUid(instanceUid);
110
+ const env = environmentToken(environment);
111
+ const base = `${canonicalAppCode}-${canonicalInstanceUid}-${env}`;
112
+ const database = `${canonicalAppCode}_${canonicalInstanceUid}_${env}`;
113
+ const mongoUsername = `${base}-rw`;
114
+ const serviceAccount = `${base}-runtime`;
115
+ const secret = `${base}-runtime`;
116
+
117
+ const lengths = {
118
+ base: base.length,
119
+ database: database.length,
120
+ mongoUsername: mongoUsername.length,
121
+ serviceAccount: serviceAccount.length,
122
+ secret: secret.length,
123
+ };
124
+ const invalidLength = Object.entries(lengths).find(([, length]) => length > 63);
125
+ if (invalidLength) {
126
+ throw new TechnicalIdentityError(
127
+ "Identidade técnica excede o orçamento DNS/Kubernetes de 63 caracteres.",
128
+ "TECHNICAL_IDENTITY_BUDGET_EXCEEDED",
129
+ { resource: invalidLength[0], length: invalidLength[1] },
130
+ );
131
+ }
132
+
133
+ return Object.freeze({
134
+ version: 1,
135
+ appCode: canonicalAppCode,
136
+ instanceUid: canonicalInstanceUid,
137
+ environment: env,
138
+ resourceBase: base,
139
+ namespace: base,
140
+ database,
141
+ mongoUsername,
142
+ serviceAccount,
143
+ secret,
144
+ });
145
+ }
146
+
147
+ module.exports = Object.freeze({
148
+ APP_CODE_MAX_LENGTH,
149
+ APP_CODE_PATTERN,
150
+ INSTANCE_UID_ALPHABET,
151
+ INSTANCE_UID_LENGTH,
152
+ INSTANCE_UID_BYTES,
153
+ INSTANCE_UID_PATTERN,
154
+ ENVIRONMENT_TOKENS,
155
+ TechnicalIdentityError,
156
+ assertAppCode,
157
+ assertInstanceUid,
158
+ environmentToken,
159
+ encodeInstanceUid,
160
+ generateInstanceUid,
161
+ technicalIdentity,
162
+ });
package/src/index.js CHANGED
@@ -10,6 +10,7 @@ const tenancy = require("./core/tenancy");
10
10
  const GenericError = require("./core/errors/GenericError");
11
11
  const { requirePermission } = require("./core/middlewares/permissions");
12
12
  const rbacPolicy = require("./core/rbac/policy");
13
+ const technicalIdentity = require("./core/technicalIdentity");
13
14
  const capabilities = require("./capabilities");
14
15
  const { operationalRequestHeaders } = require("./core/utils/instanceActivation");
15
16
  const appManifest = require("./manifest/appManifest");
@@ -75,6 +76,7 @@ module.exports = {
75
76
  drainProcessJobs: processRuntime.drainProcessJobs,
76
77
  fields,
77
78
  capabilities,
79
+ technicalIdentity,
78
80
  operationalRequestHeaders,
79
81
  licensing: {
80
82
  assertBusinessOperation: require("./core/licensing").assertBusinessOperation,
@@ -85,4 +87,4 @@ module.exports = {
85
87
  PdfRenderingError: capabilities.PdfRenderingError,
86
88
  TransactionalEmailError: capabilities.TransactionalEmailError,
87
89
  GenericError, registry,
88
- };
90
+ };