@oondemand/oon-core-back 0.3.4 → 0.3.6
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
|
@@ -27,6 +27,7 @@ const { getAppCode, getBaseUrl } = require("../core/utils/activationProvider");
|
|
|
27
27
|
|
|
28
28
|
const router = express.Router();
|
|
29
29
|
const attempts = new Map();
|
|
30
|
+
const DEV_LOCAL_PATH = "/integracao/dev-local/ativar-central";
|
|
30
31
|
|
|
31
32
|
function rateLimit(req, res, next) {
|
|
32
33
|
const key = req.ip || "local";
|
|
@@ -111,6 +112,46 @@ function requireRootBootstrapResult(result) {
|
|
|
111
112
|
};
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
function readBasicAuthorization(req) {
|
|
116
|
+
const authorization = String(req.headers.authorization || "");
|
|
117
|
+
if (!authorization.startsWith("Basic ")) {
|
|
118
|
+
throw new GenericError("Informe e-mail e senha para ativar a Central.", {
|
|
119
|
+
statusCode: 401,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return authorization;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function translateProviderActivationError(error, fallback) {
|
|
126
|
+
if (error instanceof GenericError) return error;
|
|
127
|
+
|
|
128
|
+
const timedOut = error.code === "ECONNABORTED";
|
|
129
|
+
const statusCode = timedOut ? 504 : error.response?.status || 502;
|
|
130
|
+
const message =
|
|
131
|
+
error.response?.data?.message ||
|
|
132
|
+
error.response?.data?.error?.message ||
|
|
133
|
+
(timedOut
|
|
134
|
+
? "A Central de Ativações não respondeu dentro do prazo."
|
|
135
|
+
: fallback);
|
|
136
|
+
|
|
137
|
+
return new GenericError(message, { statusCode });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function idOf(value) {
|
|
141
|
+
return value?.id || value?._id || value;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function summarizeDevInstance(data, appCode) {
|
|
145
|
+
const appId = idOf(data?.app);
|
|
146
|
+
return {
|
|
147
|
+
instanceId: `dev-local:${appId || appCode}`,
|
|
148
|
+
instanceCode: "dev-local",
|
|
149
|
+
appId: appId ? String(appId) : undefined,
|
|
150
|
+
tenantId: idOf(data?.tenant) ? String(idOf(data.tenant)) : undefined,
|
|
151
|
+
licencaId: idOf(data?.licenca) ? String(idOf(data.licenca)) : undefined,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
114
155
|
router.use(rateLimit);
|
|
115
156
|
|
|
116
157
|
router.get(
|
|
@@ -172,7 +213,8 @@ router.get(
|
|
|
172
213
|
});
|
|
173
214
|
}
|
|
174
215
|
|
|
175
|
-
const
|
|
216
|
+
const centralAtivacaoUrl = getBaseUrl(req);
|
|
217
|
+
const host = new URL(centralAtivacaoUrl).hostname;
|
|
176
218
|
return sendResponse({
|
|
177
219
|
res,
|
|
178
220
|
mode: "member-activation",
|
|
@@ -184,12 +226,14 @@ router.get(
|
|
|
184
226
|
...globalDefaults,
|
|
185
227
|
ambiente: ambiente(),
|
|
186
228
|
urlPublica: publicUrl(req),
|
|
229
|
+
nomeInstancia: ctx.config.name || ctx.config.slug || getAppCode(),
|
|
187
230
|
},
|
|
188
231
|
technical: {
|
|
189
232
|
appCode: getAppCode(),
|
|
190
233
|
ambiente: ambiente(),
|
|
191
234
|
ecosystemRole: "member",
|
|
192
235
|
centralAtivacaoHost: host,
|
|
236
|
+
centralAtivacaoUrl,
|
|
193
237
|
},
|
|
194
238
|
});
|
|
195
239
|
}),
|
|
@@ -288,6 +332,149 @@ router.post(
|
|
|
288
332
|
}),
|
|
289
333
|
);
|
|
290
334
|
|
|
335
|
+
router.post(
|
|
336
|
+
"/ativar-dev-local",
|
|
337
|
+
asyncHandler(async (req, res) => {
|
|
338
|
+
assertMember();
|
|
339
|
+
|
|
340
|
+
if (ambiente() !== "desenvolvimento") {
|
|
341
|
+
throw new GenericError(
|
|
342
|
+
"A ativação self-service está disponível somente em desenvolvimento.",
|
|
343
|
+
{ statusCode: 403 },
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const authorization = readBasicAuthorization(req);
|
|
348
|
+
const config = activationConfig();
|
|
349
|
+
const instance = await ensureInstance();
|
|
350
|
+
|
|
351
|
+
if (instance.status === "ativa") {
|
|
352
|
+
throw new GenericError("Instância já ativada.", { statusCode: 409 });
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!["nao_ativada", "validando", "erro"].includes(instance.status)) {
|
|
356
|
+
throw new GenericError(
|
|
357
|
+
"Instância não pode ser ativada neste estado.",
|
|
358
|
+
{ statusCode: 409 },
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const appCode = getAppCode();
|
|
363
|
+
const nomeCentral =
|
|
364
|
+
req.body?.nomeCentral ||
|
|
365
|
+
req.body?.appName ||
|
|
366
|
+
ctx.config.name ||
|
|
367
|
+
ctx.config.slug ||
|
|
368
|
+
appCode;
|
|
369
|
+
const urlPublica = req.body?.urlPublica || publicUrl(req);
|
|
370
|
+
|
|
371
|
+
event("DEV_LOCAL_ACTIVATION_STARTED", {
|
|
372
|
+
correlationId: req.correlationId,
|
|
373
|
+
appCode,
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
try {
|
|
377
|
+
const response = await providerPost(
|
|
378
|
+
req,
|
|
379
|
+
DEV_LOCAL_PATH,
|
|
380
|
+
{
|
|
381
|
+
appCode,
|
|
382
|
+
codigoApp: appCode,
|
|
383
|
+
nomeCentral,
|
|
384
|
+
appName: req.body?.appName || nomeCentral,
|
|
385
|
+
appSlug: req.body?.appSlug || ctx.config.slug || appCode,
|
|
386
|
+
ambiente: "desenvolvimento",
|
|
387
|
+
urlPublica,
|
|
388
|
+
repositorio: req.body?.repositorio,
|
|
389
|
+
branch: req.body?.branch,
|
|
390
|
+
nomeUsuario: req.body?.nomeUsuario,
|
|
391
|
+
nomeTenant: req.body?.nomeTenant,
|
|
392
|
+
},
|
|
393
|
+
{ Authorization: authorization },
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
const data = response.data || {};
|
|
397
|
+
assertApp(data);
|
|
398
|
+
|
|
399
|
+
const resolvedAppCode = String(
|
|
400
|
+
data.app?.codigo || data.appCode || appCode,
|
|
401
|
+
).toLowerCase();
|
|
402
|
+
const ids = summarizeDevInstance(data, resolvedAppCode);
|
|
403
|
+
const now = new Date();
|
|
404
|
+
|
|
405
|
+
Object.assign(instance, {
|
|
406
|
+
status: "ativa",
|
|
407
|
+
ecosystemRole: "member",
|
|
408
|
+
instanceId: ids.instanceId,
|
|
409
|
+
instanceCode: ids.instanceCode,
|
|
410
|
+
appCode: resolvedAppCode,
|
|
411
|
+
appId: ids.appId,
|
|
412
|
+
tenantId: ids.tenantId,
|
|
413
|
+
licencaId: ids.licencaId,
|
|
414
|
+
ambiente: "desenvolvimento",
|
|
415
|
+
nomeInstancia: nomeCentral,
|
|
416
|
+
ecosystemUrl: getBaseUrl(req),
|
|
417
|
+
publicUrl: urlPublica,
|
|
418
|
+
coreVersion: process.env.npm_package_version || "0.0.0",
|
|
419
|
+
appVersion: process.env.SERVICE_VERSION || "0.1.0",
|
|
420
|
+
credentialEncrypted: undefined,
|
|
421
|
+
credentialIv: undefined,
|
|
422
|
+
credentialAuthTag: undefined,
|
|
423
|
+
credentialVersion: undefined,
|
|
424
|
+
tenant: data.tenant,
|
|
425
|
+
app: data.app,
|
|
426
|
+
licenca: data.licenca,
|
|
427
|
+
parametrosGlobais: {
|
|
428
|
+
...globalDefaults,
|
|
429
|
+
nomeInstancia: nomeCentral,
|
|
430
|
+
ambiente: "desenvolvimento",
|
|
431
|
+
urlPublica,
|
|
432
|
+
},
|
|
433
|
+
parametrosAplicacao: {
|
|
434
|
+
devLocal: true,
|
|
435
|
+
},
|
|
436
|
+
configurationVersion: config.configurationVersion,
|
|
437
|
+
ativadaEm: now,
|
|
438
|
+
concluidaEm: now,
|
|
439
|
+
ultimaValidacaoEm: now,
|
|
440
|
+
ultimoErro: undefined,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
await instance.save();
|
|
444
|
+
|
|
445
|
+
event("DEV_LOCAL_ACTIVATION_COMPLETED", {
|
|
446
|
+
correlationId: req.correlationId,
|
|
447
|
+
appCode: resolvedAppCode,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
sendResponse({
|
|
451
|
+
res,
|
|
452
|
+
statusCode: 201,
|
|
453
|
+
...data,
|
|
454
|
+
message: data.message || "Central ativada em desenvolvimento local.",
|
|
455
|
+
sucesso: true,
|
|
456
|
+
status: "ativa",
|
|
457
|
+
instanceId: instance.instanceId,
|
|
458
|
+
});
|
|
459
|
+
} catch (error) {
|
|
460
|
+
instance.status = "erro";
|
|
461
|
+
instance.ultimoErro = error.response?.data?.message || error.message;
|
|
462
|
+
await instance.save();
|
|
463
|
+
|
|
464
|
+
event("DEV_LOCAL_ACTIVATION_FAILED", {
|
|
465
|
+
correlationId: req.correlationId,
|
|
466
|
+
appCode,
|
|
467
|
+
status: error.response?.status,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
throw translateProviderActivationError(
|
|
471
|
+
error,
|
|
472
|
+
"Não foi possível ativar a Central em desenvolvimento local.",
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
}),
|
|
476
|
+
);
|
|
477
|
+
|
|
291
478
|
router.post(
|
|
292
479
|
"/validar-codigo",
|
|
293
480
|
asyncHandler(async (req, res) => {
|
|
@@ -1,25 +1,40 @@
|
|
|
1
1
|
const GenericError = require("../errors/GenericError");
|
|
2
|
+
const ctx = require("../context");
|
|
2
3
|
|
|
4
|
+
const DEFAULT_CENTRAL_ATIVACAO_URL =
|
|
5
|
+
"https://central-ativacao.central.oondemand.online";
|
|
3
6
|
const LOGIN_PATH = "/integracao/autenticacao-aplicativos/autenticar";
|
|
4
7
|
const PERMISSION_PATH = "/integracao/autenticacao-aplicativos/verificar-permissao";
|
|
5
8
|
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
throw new GenericError("CENTRAL_ATIVACAO_URL não configurada.", {
|
|
10
|
-
statusCode: 500,
|
|
11
|
-
});
|
|
12
|
-
}
|
|
9
|
+
function uniq(values) {
|
|
10
|
+
return [...new Set(values.filter(Boolean))];
|
|
11
|
+
}
|
|
13
12
|
|
|
13
|
+
function normalizeBaseUrl(value, label) {
|
|
14
14
|
let parsed;
|
|
15
15
|
try {
|
|
16
16
|
parsed = new URL(value);
|
|
17
17
|
} catch {
|
|
18
|
-
throw new GenericError(
|
|
18
|
+
throw new GenericError(`${label} inválida.`, {
|
|
19
19
|
statusCode: 500,
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
return parsed.toString().replace(/\/$/, "");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function withApiPath(value) {
|
|
27
|
+
const parsed = new URL(value);
|
|
28
|
+
const cleanPath = parsed.pathname.replace(/\/$/, "");
|
|
29
|
+
|
|
30
|
+
if (cleanPath.endsWith("/api")) return null;
|
|
31
|
+
|
|
32
|
+
parsed.pathname = `${cleanPath}/api`.replace(/^\/\//, "/");
|
|
33
|
+
return parsed.toString().replace(/\/$/, "");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function assertNotSameHost(url, req) {
|
|
37
|
+
const parsed = new URL(url);
|
|
23
38
|
const currentHost = String(
|
|
24
39
|
req?.headers?.["x-forwarded-host"] || req?.headers?.host || "",
|
|
25
40
|
)
|
|
@@ -37,8 +52,66 @@ function getBaseUrl(req) {
|
|
|
37
52
|
{ statusCode: 500 },
|
|
38
53
|
);
|
|
39
54
|
}
|
|
55
|
+
}
|
|
40
56
|
|
|
41
|
-
|
|
57
|
+
function readCentralActivationPublicUrl() {
|
|
58
|
+
return (
|
|
59
|
+
process.env.CENTRAL_ATIVACAO_URL ||
|
|
60
|
+
process.env.MEUS_APPS_BACKEND_URL ||
|
|
61
|
+
DEFAULT_CENTRAL_ATIVACAO_URL
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readCentralActivationApiUrl() {
|
|
66
|
+
return (
|
|
67
|
+
process.env.CENTRAL_ATIVACAO_API_URL ||
|
|
68
|
+
process.env.CENTRAL_ATIVACAO_BACKEND_URL ||
|
|
69
|
+
process.env.CENTRAL_ATIVACAO_URL ||
|
|
70
|
+
process.env.MEUS_APPS_BACKEND_URL ||
|
|
71
|
+
DEFAULT_CENTRAL_ATIVACAO_URL
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getBaseUrl(req) {
|
|
76
|
+
const value = normalizeBaseUrl(
|
|
77
|
+
readCentralActivationApiUrl(),
|
|
78
|
+
"CENTRAL_ATIVACAO_API_URL/CENTRAL_ATIVACAO_URL",
|
|
79
|
+
);
|
|
80
|
+
assertNotSameHost(value, req);
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getDisplayUrl(req) {
|
|
85
|
+
const value = normalizeBaseUrl(
|
|
86
|
+
readCentralActivationPublicUrl(),
|
|
87
|
+
"CENTRAL_ATIVACAO_URL",
|
|
88
|
+
);
|
|
89
|
+
assertNotSameHost(value, req);
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getBaseUrlCandidates(req) {
|
|
94
|
+
const explicitApi = process.env.CENTRAL_ATIVACAO_API_URL;
|
|
95
|
+
const raw = uniq([
|
|
96
|
+
process.env.CENTRAL_ATIVACAO_API_URL,
|
|
97
|
+
process.env.CENTRAL_ATIVACAO_BACKEND_URL,
|
|
98
|
+
process.env.CENTRAL_ATIVACAO_URL,
|
|
99
|
+
process.env.MEUS_APPS_BACKEND_URL,
|
|
100
|
+
DEFAULT_CENTRAL_ATIVACAO_URL,
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
const normalized = raw.map((value) =>
|
|
104
|
+
normalizeBaseUrl(value, "CENTRAL_ATIVACAO_API_URL/CENTRAL_ATIVACAO_URL"),
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const expanded = explicitApi
|
|
108
|
+
? normalized
|
|
109
|
+
: normalized.flatMap((value) => [value, withApiPath(value)]);
|
|
110
|
+
|
|
111
|
+
return uniq(expanded).map((url) => {
|
|
112
|
+
assertNotSameHost(url, req);
|
|
113
|
+
return url;
|
|
114
|
+
});
|
|
42
115
|
}
|
|
43
116
|
|
|
44
117
|
function getAppCode() {
|
|
@@ -47,6 +120,9 @@ function getAppCode() {
|
|
|
47
120
|
process.env.APP_CODIGO ||
|
|
48
121
|
process.env.OON_APP_CODE ||
|
|
49
122
|
process.env.OON_APP_CODIGO ||
|
|
123
|
+
ctx.config.appCode ||
|
|
124
|
+
ctx.config.appCodigo ||
|
|
125
|
+
ctx.config.slug ||
|
|
50
126
|
"",
|
|
51
127
|
)
|
|
52
128
|
.trim()
|
|
@@ -66,9 +142,12 @@ function getTimeout() {
|
|
|
66
142
|
}
|
|
67
143
|
|
|
68
144
|
module.exports = {
|
|
145
|
+
DEFAULT_CENTRAL_ATIVACAO_URL,
|
|
69
146
|
LOGIN_PATH,
|
|
70
147
|
PERMISSION_PATH,
|
|
71
148
|
getBaseUrl,
|
|
149
|
+
getDisplayUrl,
|
|
150
|
+
getBaseUrlCandidates,
|
|
72
151
|
getAppCode,
|
|
73
152
|
getTimeout,
|
|
74
153
|
};
|
|
@@ -4,7 +4,12 @@ const axios = require("axios");
|
|
|
4
4
|
const ctx = require("../context");
|
|
5
5
|
const GenericError = require("../errors/GenericError");
|
|
6
6
|
const Instancia = require("../models/InstanciaEcossistema");
|
|
7
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
getBaseUrl,
|
|
9
|
+
getBaseUrlCandidates,
|
|
10
|
+
getAppCode,
|
|
11
|
+
getTimeout,
|
|
12
|
+
} = require("./activationProvider");
|
|
8
13
|
|
|
9
14
|
const PATHS = {
|
|
10
15
|
validar: "/integracao/ativacao-instancias/validar-codigo",
|
|
@@ -430,12 +435,28 @@ function validateParams(globalParameters = {}, appParameters = {}) {
|
|
|
430
435
|
}
|
|
431
436
|
}
|
|
432
437
|
|
|
438
|
+
function shouldTryNextProviderUrl(error) {
|
|
439
|
+
return [404, 405].includes(Number(error.response?.status));
|
|
440
|
+
}
|
|
441
|
+
|
|
433
442
|
async function providerPost(req, path, payload, headers = {}) {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
443
|
+
const baseUrls = getBaseUrlCandidates(req);
|
|
444
|
+
let lastError;
|
|
445
|
+
|
|
446
|
+
for (const baseUrl of baseUrls) {
|
|
447
|
+
try {
|
|
448
|
+
return await axios.post(`${baseUrl}${path}`, payload, {
|
|
449
|
+
timeout: getTimeout(),
|
|
450
|
+
maxRedirects: 0,
|
|
451
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
452
|
+
});
|
|
453
|
+
} catch (error) {
|
|
454
|
+
lastError = error;
|
|
455
|
+
if (!shouldTryNextProviderUrl(error)) throw error;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
throw lastError;
|
|
439
460
|
}
|
|
440
461
|
|
|
441
462
|
function providerPayload(req, codigoAtivacao, extra = {}) {
|