@oondemand/oon-core-back 0.7.9 → 0.7.11
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
|
@@ -637,18 +637,51 @@ router.post(
|
|
|
637
637
|
});
|
|
638
638
|
}
|
|
639
639
|
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
640
|
+
const payload = providerPayload(req, codigoAtivacao, { nomeInstancia, metadata: {} });
|
|
641
|
+
const crypto = require("node:crypto");
|
|
642
|
+
const { fingerprint: _fingerprint, coreVersion: _coreVersion, appVersion: _appVersion, ...semanticPayload } = payload;
|
|
643
|
+
const payloadHash = crypto.createHash("sha256").update(JSON.stringify({ payload: semanticPayload, parametrosGlobais, parametrosAplicacao,
|
|
644
|
+
configurationVersion: config.configurationVersion })).digest("hex");
|
|
645
|
+
const requestedKey = req.headers["idempotency-key"];
|
|
646
|
+
if (requestedKey && (typeof requestedKey !== "string" || requestedKey.length < 8 || requestedKey.length > 120))
|
|
647
|
+
throw new GenericError("Chave de ativação inválida.", { statusCode: 422, code: "IDEMPOTENCY_KEY_REQUIRED" });
|
|
648
|
+
if (instance.activationRequest && (instance.activationRequest.payloadHash !== payloadHash
|
|
649
|
+
|| requestedKey && requestedKey !== instance.activationRequest.key))
|
|
650
|
+
throw new GenericError("Retome a mesma intenção de ativação.", { statusCode: 409, code: "IDEMPOTENCY_CONFLICT" });
|
|
651
|
+
const preview = instance.activationRequest ? { data: {} } : await activationProviderPost(
|
|
652
|
+
req, PATHS.validar, providerPayload(req, codigoAtivacao));
|
|
645
653
|
assertApp(preview.data);
|
|
646
654
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
655
|
+
// Persist identity before the provider can consume the activation code.
|
|
656
|
+
// A lost reply retries that command, including after process restart.
|
|
657
|
+
// Keep runtime-generated fields across replica/container replacement. The
|
|
658
|
+
// activation code itself is supplied again by the caller, never stored here.
|
|
659
|
+
const { codigoAtivacao: _code, ...providerContext } = payload;
|
|
660
|
+
const intent = instance.activationRequest || { key: requestedKey || crypto.randomUUID(), payloadHash, providerContext };
|
|
661
|
+
const Instance = require("../core/models/InstanciaEcossistema");
|
|
662
|
+
await Instance.updateOne({ _id: instance._id, activationRequest: null }, { $set: { activationRequest: intent } });
|
|
663
|
+
const saved = await Instance.findById(instance._id).select("+activationRequest").lean();
|
|
664
|
+
if (!saved || saved.activationRequest?.payloadHash !== payloadHash || requestedKey && saved.activationRequest.key !== requestedKey)
|
|
665
|
+
throw new GenericError("Outra intenção de ativação está pendente.", { statusCode: 409, code: "IDEMPOTENCY_CONFLICT" });
|
|
666
|
+
instance.activationRequest = saved.activationRequest;
|
|
667
|
+
|
|
668
|
+
let activated;
|
|
669
|
+
try {
|
|
670
|
+
activated = await activationProviderPost(req, PATHS.ativar,
|
|
671
|
+
{ ...instance.activationRequest.providerContext, codigoAtivacao },
|
|
672
|
+
{ "Idempotency-Key": instance.activationRequest.key });
|
|
673
|
+
} catch (error) {
|
|
674
|
+
// Only an explicit, durable provider outcome can release the local intent.
|
|
675
|
+
// Timeouts, generic 4xx/5xx and a used/revoked credential remain uncertain.
|
|
676
|
+
if (error.code === "ACTIVATION_NOT_COMMITTED"
|
|
677
|
+
&& error.details?.operationId === instance.activationRequest.key
|
|
678
|
+
&& error.details?.activationOutcome === "not_committed") {
|
|
679
|
+
await Instance.updateOne({ _id: instance._id, "activationRequest.key": instance.activationRequest.key,
|
|
680
|
+
"activationRequest.payloadHash": payloadHash, deploymentId: null, instanceId: null },
|
|
681
|
+
{ $unset: { activationRequest: 1 } });
|
|
682
|
+
}
|
|
683
|
+
throw error;
|
|
684
|
+
}
|
|
652
685
|
assertApp(activated.data);
|
|
653
686
|
|
|
654
687
|
const token = activated.data?.credencial?.token || activated.data?.deploymentCredential?.token;
|
|
@@ -688,6 +721,7 @@ router.post(
|
|
|
688
721
|
parametrosGlobais,
|
|
689
722
|
parametrosAplicacao,
|
|
690
723
|
configurationVersion: config.configurationVersion,
|
|
724
|
+
publicationIdentity: activated.data.publicationIdentity,
|
|
691
725
|
ativadaEm: new Date(),
|
|
692
726
|
ultimoErro: undefined,
|
|
693
727
|
});
|
|
@@ -724,8 +758,11 @@ async function complete(req, instance, config) {
|
|
|
724
758
|
{
|
|
725
759
|
configurationVersion: config.configurationVersion,
|
|
726
760
|
parametros: instance.parametrosGlobais,
|
|
761
|
+
...(instance.publicationIdentity ? { publicationIdentity: instance.publicationIdentity } : {}),
|
|
727
762
|
},
|
|
728
|
-
instanceHeaders(instance),
|
|
763
|
+
{ ...instanceHeaders(instance), ...(instance.publicationIdentity ? {
|
|
764
|
+
"Idempotency-Key": `configuration:${instance.publicationIdentity.releaseId}:${config.configurationVersion}`,
|
|
765
|
+
} : {}) },
|
|
729
766
|
);
|
|
730
767
|
|
|
731
768
|
instance.status = "ativa";
|
|
@@ -30,6 +30,8 @@ const schema = new mongoose.Schema(
|
|
|
30
30
|
credentialAuthTag: { type: String, select: false },
|
|
31
31
|
credentialVersion: Number,
|
|
32
32
|
configurationVersion: Number,
|
|
33
|
+
publicationIdentity: { type: mongoose.Schema.Types.Mixed },
|
|
34
|
+
activationRequest: { type: mongoose.Schema.Types.Mixed, select: false },
|
|
33
35
|
parametrosGlobais: { type: mongoose.Schema.Types.Mixed, default: {} },
|
|
34
36
|
parametrosAplicacao: { type: mongoose.Schema.Types.Mixed, default: {} },
|
|
35
37
|
tenant: { type: mongoose.Schema.Types.Mixed, default: {} },
|
|
@@ -54,6 +56,7 @@ const schema = new mongoose.Schema(
|
|
|
54
56
|
delete ret.credentialEncrypted;
|
|
55
57
|
delete ret.credentialIv;
|
|
56
58
|
delete ret.credentialAuthTag;
|
|
59
|
+
delete ret.activationRequest;
|
|
57
60
|
return ret;
|
|
58
61
|
},
|
|
59
62
|
},
|
|
@@ -127,9 +127,14 @@ function deploymentBootstrap() {
|
|
|
127
127
|
}
|
|
128
128
|
const tenancyModel =
|
|
129
129
|
ctx.config.tenancyModel || ctx.config.ecosystem?.tenancyModel;
|
|
130
|
-
|
|
130
|
+
const shared = tenancyModel === "multi_tenant"
|
|
131
|
+
&& (ctx.config.deploymentMode || ctx.config.ecosystem?.deploymentMode) === "shared"
|
|
132
|
+
&& (ctx.config.availability || ctx.config.ecosystem?.availability) === "common"
|
|
133
|
+
&& (ctx.config.accessMode || ctx.config.ecosystem?.accessMode) === "tenant_members"
|
|
134
|
+
&& (ctx.config.authorizationMode || ctx.config.ecosystem?.authorizationMode) === "rbac";
|
|
135
|
+
if (tenancyModel !== "none" && !shared) {
|
|
131
136
|
throw new GenericError(
|
|
132
|
-
"Bootstrap direto
|
|
137
|
+
"Bootstrap direto exige App global ou comum multi-tenant/shared.",
|
|
133
138
|
{ statusCode: 500, code: "DEPLOYMENT_BOOTSTRAP_TENANCY_INVALID" },
|
|
134
139
|
);
|
|
135
140
|
}
|
|
@@ -249,6 +254,8 @@ function clearInstanceIdentity(instance) {
|
|
|
249
254
|
instance.credentialEncrypted = undefined;
|
|
250
255
|
instance.credentialIv = undefined;
|
|
251
256
|
instance.credentialAuthTag = undefined;
|
|
257
|
+
instance.publicationIdentity = undefined;
|
|
258
|
+
instance.activationRequest = undefined;
|
|
252
259
|
}
|
|
253
260
|
|
|
254
261
|
async function ensureInstance() {
|
|
@@ -273,7 +280,7 @@ async function ensureInstance() {
|
|
|
273
280
|
}
|
|
274
281
|
|
|
275
282
|
let instance = await Instancia.findOne().select(
|
|
276
|
-
"+credentialEncrypted +credentialIv +credentialAuthTag",
|
|
283
|
+
"+credentialEncrypted +credentialIv +credentialAuthTag +activationRequest",
|
|
277
284
|
);
|
|
278
285
|
|
|
279
286
|
if (!instance) {
|