@saasicat/nest 0.8.0 → 0.10.0
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/dist/_entries.cjs +17678 -0
- package/dist/admin/index.cjs +4 -1274
- package/dist/admin/index.d.cts +10 -171
- package/dist/admin/index.d.ts +10 -171
- package/dist/admin/index.js +13 -4
- package/dist/admin-resources.module-BZN_yBFj.d.cts +40 -0
- package/dist/admin-resources.module-Cms8MY6h.d.ts +40 -0
- package/dist/admin-stats.module-15ac5KY3.d.ts +201 -0
- package/dist/admin-stats.module-v4SVvWzj.d.cts +201 -0
- package/dist/billing/index.cjs +4 -5128
- package/dist/billing/index.d.cts +8 -719
- package/dist/billing/index.d.ts +8 -719
- package/dist/billing/index.js +7 -10
- package/dist/catalog/index.cjs +4 -5624
- package/dist/catalog/index.d.cts +7 -427
- package/dist/catalog/index.d.ts +7 -427
- package/dist/catalog/index.js +14 -12
- package/dist/catalog.module-BKObceo0.d.ts +103 -0
- package/dist/catalog.module-Dw2Hrbyu.d.cts +103 -0
- package/dist/checkout-offer/index.cjs +4 -807
- package/dist/checkout-offer/index.d.cts +5 -84
- package/dist/checkout-offer/index.d.ts +5 -84
- package/dist/checkout-offer/index.js +3 -2
- package/dist/checkout-offer.module-Y0hDOVrq.d.ts +85 -0
- package/dist/checkout-offer.module-ZYF5IsDY.d.cts +85 -0
- package/dist/{chunk-5DDCSGZC.js → chunk-33TP26MR.js} +144 -356
- package/dist/{chunk-CK54YKVK.js → chunk-75JABGZK.js} +16 -16
- package/dist/{chunk-HRU3CP57.js → chunk-BOADBIGB.js} +1 -1
- package/dist/{chunk-ZLUGQE5D.js → chunk-E7AJ42AB.js} +8 -8
- package/dist/{chunk-6LP7CDS2.js → chunk-F3VV6EXG.js} +18 -13
- package/dist/{chunk-PLDHI6NA.js → chunk-FVT7KTUI.js} +258 -3
- package/dist/{chunk-RZU4HIAN.js → chunk-GBDUH6DO.js} +26 -23
- package/dist/{chunk-K3OPNVFR.js → chunk-HBFU5AN3.js} +5 -9
- package/dist/chunk-HWGIMNWR.js +0 -0
- package/dist/chunk-IRWZC3GC.js +755 -0
- package/dist/chunk-L4KTQ6CL.js +20 -0
- package/dist/{chunk-T5SXXAKG.js → chunk-LZHLGUQI.js} +1 -1
- package/dist/{chunk-YHHE4KDA.js → chunk-PUXLPUVH.js} +351 -21
- package/dist/chunk-TXDH4FUA.js +211 -0
- package/dist/chunk-UF53DWWR.js +0 -0
- package/dist/{chunk-AJ3EPELS.js → chunk-V34AA7C7.js} +1 -1
- package/dist/chunk-WJ6BMDL3.js +313 -0
- package/dist/{chunk-M6CZQYPY.js → chunk-Z3FWN3HJ.js} +2 -2
- package/dist/discovery/index.cjs +4 -588
- package/dist/discovery/index.js +3 -3
- package/dist/{enforce-quota.interceptor-cv7r80VM.d.cts → enforce-quota.interceptor-BhkX5nq2.d.cts} +127 -12
- package/dist/{enforce-quota.interceptor-Dj1Kusr5.d.ts → enforce-quota.interceptor-CcqZc0Yu.d.ts} +127 -12
- package/dist/entitlement/index.cjs +4 -780
- package/dist/entitlement/index.d.cts +3 -1
- package/dist/entitlement/index.d.ts +3 -1
- package/dist/entitlement/index.js +2 -3
- package/dist/index.cjs +4 -14975
- package/dist/index.d.cts +22 -54
- package/dist/index.d.ts +22 -54
- package/dist/index.js +88 -369
- package/dist/module-CSN8j8Tp.d.cts +39 -0
- package/dist/module-DgYJur6f.d.ts +39 -0
- package/dist/plan-versions.service-BB36Q1bg.d.ts +329 -0
- package/dist/plan-versions.service-CUR2Whyr.d.cts +329 -0
- package/dist/platform/index.cjs +4 -2779
- package/dist/platform/index.d.cts +50 -8
- package/dist/platform/index.d.ts +50 -8
- package/dist/platform/index.js +116 -12
- package/dist/promo/index.cjs +4 -995
- package/dist/promo/index.d.cts +48 -46
- package/dist/promo/index.d.ts +48 -46
- package/dist/promo/index.js +10 -2
- package/dist/rate-limit.guard-dntqAlfZ.d.cts +19 -0
- package/dist/rate-limit.guard-dntqAlfZ.d.ts +19 -0
- package/dist/registration/index.cjs +4 -1655
- package/dist/registration/index.js +1 -1
- package/dist/setup.service-BPwJ7My_.d.cts +45 -0
- package/dist/setup.service-D2mrdDDB.d.ts +45 -0
- package/dist/subscription-bundle-preview.service-BkJXHAeP.d.cts +438 -0
- package/dist/subscription-bundle-preview.service-DBbrE_cw.d.ts +438 -0
- package/dist/subscription-bundles.module-BQmoozm5.d.ts +291 -0
- package/dist/subscription-bundles.module-DCpV-Pb5.d.cts +291 -0
- package/dist/subscription-contract/index.cjs +4 -471
- package/dist/subscription-contract/index.d.cts +5 -13
- package/dist/subscription-contract/index.d.ts +5 -13
- package/dist/subscription-contract.module-CG9fPKAr.d.cts +14 -0
- package/dist/subscription-contract.module-CVebZzHR.d.ts +14 -0
- package/dist/testing/index.cjs +4 -3756
- package/dist/testing/index.d.cts +9 -4
- package/dist/testing/index.d.ts +9 -4
- package/dist/testing/index.js +13 -7
- package/package.json +5 -5
- package/dist/admin-manifest.config-DyrQNT7M.d.cts +0 -10
- package/dist/admin-manifest.config-DyrQNT7M.d.ts +0 -10
- package/dist/admin-manifest.service-Cp6uwvmt.d.cts +0 -33
- package/dist/admin-manifest.service-UGgzR1x-.d.ts +0 -33
- package/dist/chunk-52UTQRD3.js +0 -326
- package/dist/chunk-N3WANKSA.js +0 -20
- package/dist/chunk-Q53N43LQ.js +0 -13
- /package/dist/{chunk-2FR6ZL7R.js → chunk-DBZGV3HC.js} +0 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DiscoverySnapshotNotFoundError,
|
|
3
|
+
loadDiscoverySnapshotFromFile
|
|
4
|
+
} from "./chunk-ABB2CRAS.js";
|
|
5
|
+
import {
|
|
6
|
+
ADVISORY_STRICT_MODE_CODES,
|
|
7
|
+
validateBundleDraft,
|
|
8
|
+
validatePlanDraft
|
|
9
|
+
} from "./chunk-33TP26MR.js";
|
|
10
|
+
import {
|
|
11
|
+
__name
|
|
12
|
+
} from "./chunk-SHUYVCID.js";
|
|
13
|
+
|
|
14
|
+
// src/catalog/preflight.ts
|
|
15
|
+
function runPreflight(input) {
|
|
16
|
+
const findings = [];
|
|
17
|
+
const approved = input.approved ?? null;
|
|
18
|
+
for (const pv of input.planVersions) {
|
|
19
|
+
const warns = validatePlanDraft({
|
|
20
|
+
features: pv.features,
|
|
21
|
+
quotas: pv.quotas ?? {}
|
|
22
|
+
}, input.snapshot, /* @__PURE__ */ new Set(), approved);
|
|
23
|
+
for (const w of warns) {
|
|
24
|
+
findings.push({
|
|
25
|
+
kind: "plan",
|
|
26
|
+
versionId: pv.id,
|
|
27
|
+
entityKey: pv.planId,
|
|
28
|
+
version: pv.version,
|
|
29
|
+
warning: w
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const bv of input.bundleVersions) {
|
|
34
|
+
const warns = validateBundleDraft({
|
|
35
|
+
features: bv.features,
|
|
36
|
+
quotas: bv.quotas ?? {}
|
|
37
|
+
}, input.snapshot, null, /* @__PURE__ */ new Set(), approved);
|
|
38
|
+
for (const w of warns) {
|
|
39
|
+
findings.push({
|
|
40
|
+
kind: "bundle",
|
|
41
|
+
versionId: bv.id,
|
|
42
|
+
entityKey: bv.bundleKey,
|
|
43
|
+
version: bv.version,
|
|
44
|
+
warning: w
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
findings.sort((a, b) => {
|
|
49
|
+
if (a.kind !== b.kind) return a.kind.localeCompare(b.kind);
|
|
50
|
+
if (a.entityKey !== b.entityKey) return a.entityKey.localeCompare(b.entityKey);
|
|
51
|
+
if (a.version !== b.version) return a.version - b.version;
|
|
52
|
+
return a.warning.code.localeCompare(b.warning.code);
|
|
53
|
+
});
|
|
54
|
+
const counts = {
|
|
55
|
+
planFindings: findings.filter((f) => f.kind === "plan").length,
|
|
56
|
+
bundleFindings: findings.filter((f) => f.kind === "bundle").length,
|
|
57
|
+
total: findings.length
|
|
58
|
+
};
|
|
59
|
+
const hasBlockingFinding = findings.some((f) => !ADVISORY_STRICT_MODE_CODES.has(f.warning.code));
|
|
60
|
+
return {
|
|
61
|
+
overall: hasBlockingFinding ? "error" : "ok",
|
|
62
|
+
counts,
|
|
63
|
+
findings
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
__name(runPreflight, "runPreflight");
|
|
67
|
+
function formatPreflightReport(report) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
lines.push(`Preflight (Status: ${report.overall.toUpperCase()})`, ` Plans: ${report.counts.planFindings} \xB7 Bundles: ${report.counts.bundleFindings} \xB7 Gesamt: ${report.counts.total}`, "");
|
|
70
|
+
if (report.findings.length === 0) {
|
|
71
|
+
lines.push(" \u2713 Keine Strict-Mode-Verst\xF6\xDFe gefunden.");
|
|
72
|
+
return lines.join("\n");
|
|
73
|
+
}
|
|
74
|
+
let lastEntity = "";
|
|
75
|
+
for (const f of report.findings) {
|
|
76
|
+
const entityHeader = `${f.kind} ${f.entityKey} v${f.version}`;
|
|
77
|
+
if (entityHeader !== lastEntity) {
|
|
78
|
+
lines.push(` \u2717 ${entityHeader} (${f.versionId})`);
|
|
79
|
+
lastEntity = entityHeader;
|
|
80
|
+
}
|
|
81
|
+
const fieldHint = f.warning.field ? ` [${f.warning.field}]` : "";
|
|
82
|
+
lines.push(` ${f.warning.code}${fieldHint}: ${f.warning.message}`);
|
|
83
|
+
}
|
|
84
|
+
return lines.join("\n");
|
|
85
|
+
}
|
|
86
|
+
__name(formatPreflightReport, "formatPreflightReport");
|
|
87
|
+
function preflightExitCode(report) {
|
|
88
|
+
return report.overall === "error" ? 4 : 0;
|
|
89
|
+
}
|
|
90
|
+
__name(preflightExitCode, "preflightExitCode");
|
|
91
|
+
|
|
92
|
+
// src/catalog/seed-gate.ts
|
|
93
|
+
function validateSeedAgainstSnapshot(input) {
|
|
94
|
+
const findings = [];
|
|
95
|
+
for (const plan of input.plans ?? []) {
|
|
96
|
+
const warns = validatePlanDraft({
|
|
97
|
+
features: plan.features,
|
|
98
|
+
quotas: plan.quotas ?? {}
|
|
99
|
+
}, input.snapshot, /* @__PURE__ */ new Set(), input.approved ?? null);
|
|
100
|
+
for (const warning of warns) {
|
|
101
|
+
findings.push({
|
|
102
|
+
kind: "plan",
|
|
103
|
+
entityKey: plan.planKey,
|
|
104
|
+
warning
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (const bundle of input.bundles ?? []) {
|
|
109
|
+
const warns = validateBundleDraft({
|
|
110
|
+
features: bundle.features,
|
|
111
|
+
quotas: bundle.quotas ?? {}
|
|
112
|
+
}, input.snapshot, null, /* @__PURE__ */ new Set(), input.approved ?? null);
|
|
113
|
+
for (const warning of warns) {
|
|
114
|
+
findings.push({
|
|
115
|
+
kind: "bundle",
|
|
116
|
+
entityKey: bundle.bundleKey,
|
|
117
|
+
warning
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
findings.sort((a, b) => {
|
|
122
|
+
if (a.kind !== b.kind) return a.kind.localeCompare(b.kind);
|
|
123
|
+
if (a.entityKey !== b.entityKey) return a.entityKey.localeCompare(b.entityKey);
|
|
124
|
+
return a.warning.code.localeCompare(b.warning.code);
|
|
125
|
+
});
|
|
126
|
+
const counts = {
|
|
127
|
+
planFindings: findings.filter((f) => f.kind === "plan").length,
|
|
128
|
+
bundleFindings: findings.filter((f) => f.kind === "bundle").length,
|
|
129
|
+
total: findings.length
|
|
130
|
+
};
|
|
131
|
+
const hasBlockingFinding = findings.some((f) => !ADVISORY_STRICT_MODE_CODES.has(f.warning.code));
|
|
132
|
+
return {
|
|
133
|
+
overall: hasBlockingFinding ? "error" : "ok",
|
|
134
|
+
counts,
|
|
135
|
+
findings
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
__name(validateSeedAgainstSnapshot, "validateSeedAgainstSnapshot");
|
|
139
|
+
function formatSeedGateReport(report) {
|
|
140
|
+
const lines = [];
|
|
141
|
+
lines.push(`Seed-Gate (Status: ${report.overall.toUpperCase()})`, ` Plans: ${report.counts.planFindings} \xB7 Bundles: ${report.counts.bundleFindings} \xB7 Gesamt: ${report.counts.total}`, "");
|
|
142
|
+
if (report.findings.length === 0) {
|
|
143
|
+
lines.push(" \u2713 Alle geseedeten Plan-/Bundle-Features sind discovered (und, sofern gepr\xFCft, approved).");
|
|
144
|
+
return lines.join("\n");
|
|
145
|
+
}
|
|
146
|
+
let lastEntity = "";
|
|
147
|
+
for (const f of report.findings) {
|
|
148
|
+
const entityHeader = `${f.kind} ${f.entityKey}`;
|
|
149
|
+
if (entityHeader !== lastEntity) {
|
|
150
|
+
lines.push(` \u2717 ${entityHeader}`);
|
|
151
|
+
lastEntity = entityHeader;
|
|
152
|
+
}
|
|
153
|
+
const fieldHint = f.warning.field ? ` [${f.warning.field}]` : "";
|
|
154
|
+
lines.push(` ${f.warning.code}${fieldHint}: ${f.warning.message}`);
|
|
155
|
+
}
|
|
156
|
+
return lines.join("\n");
|
|
157
|
+
}
|
|
158
|
+
__name(formatSeedGateReport, "formatSeedGateReport");
|
|
159
|
+
function seedGateExitCode(report) {
|
|
160
|
+
return report.overall === "error" ? 4 : 0;
|
|
161
|
+
}
|
|
162
|
+
__name(seedGateExitCode, "seedGateExitCode");
|
|
163
|
+
|
|
164
|
+
// src/catalog/seed-gate-runner.ts
|
|
165
|
+
function runSeedGateFromFile(options) {
|
|
166
|
+
const mode = options.mode ?? "report-only";
|
|
167
|
+
const log = options.log ?? ((line) => console.log(line));
|
|
168
|
+
const warn = options.warn ?? ((line) => console.warn(line));
|
|
169
|
+
const error = options.error ?? ((line) => console.error(line));
|
|
170
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
171
|
+
let snapshot;
|
|
172
|
+
try {
|
|
173
|
+
snapshot = loadDiscoverySnapshotFromFile(options.snapshotPath);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
if (err instanceof DiscoverySnapshotNotFoundError) {
|
|
176
|
+
if (mode === "blocking") {
|
|
177
|
+
error(`[seed-gate] FEHLER: Kein Discovery-Snapshot unter ${options.snapshotPath} \u2014 im blocking-Modus Pflicht (Headless-Scan vor dem Seed ausf\xFChren, #23).`);
|
|
178
|
+
return exit(4);
|
|
179
|
+
}
|
|
180
|
+
warn(`[seed-gate] Kein Discovery-Snapshot unter ${options.snapshotPath} \u2014 \xFCbersprungen (report-only).`);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
throw err;
|
|
184
|
+
}
|
|
185
|
+
const report = validateSeedAgainstSnapshot({
|
|
186
|
+
snapshot,
|
|
187
|
+
plans: options.plans,
|
|
188
|
+
bundles: options.bundles,
|
|
189
|
+
approved: options.approved ?? null
|
|
190
|
+
});
|
|
191
|
+
log(formatSeedGateReport(report));
|
|
192
|
+
if (report.overall === "error") {
|
|
193
|
+
if (mode === "blocking") {
|
|
194
|
+
error("[seed-gate] blocking: Verst\xF6\xDFe gefunden \u2014 Seed wird abgebrochen (#23).");
|
|
195
|
+
return exit(seedGateExitCode(report));
|
|
196
|
+
}
|
|
197
|
+
warn("[seed-gate] report-only: Verst\xF6\xDFe gefunden, Seed l\xE4uft trotzdem weiter.");
|
|
198
|
+
}
|
|
199
|
+
return report;
|
|
200
|
+
}
|
|
201
|
+
__name(runSeedGateFromFile, "runSeedGateFromFile");
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
runPreflight,
|
|
205
|
+
formatPreflightReport,
|
|
206
|
+
preflightExitCode,
|
|
207
|
+
validateSeedAgainstSnapshot,
|
|
208
|
+
formatSeedGateReport,
|
|
209
|
+
seedGateExitCode,
|
|
210
|
+
runSeedGateFromFile
|
|
211
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MfaService
|
|
3
|
+
} from "./chunk-FVT7KTUI.js";
|
|
4
|
+
import {
|
|
5
|
+
asProvider
|
|
6
|
+
} from "./chunk-SABTXESR.js";
|
|
7
|
+
import {
|
|
8
|
+
__name
|
|
9
|
+
} from "./chunk-SHUYVCID.js";
|
|
10
|
+
|
|
11
|
+
// src/setup/tokens.ts
|
|
12
|
+
var SETUP_PROVISIONING_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/SetupProvisioningPort");
|
|
13
|
+
var SETUP_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/SetupConfig");
|
|
14
|
+
|
|
15
|
+
// src/setup/setup.service.ts
|
|
16
|
+
import { BadRequestException, ConflictException, ForbiddenException, Inject, Injectable, UnauthorizedException } from "@nestjs/common";
|
|
17
|
+
import { isPlatformUserExistsError, SETUP_ERROR_CODES } from "@saasicat/types";
|
|
18
|
+
import { randomBytes, timingSafeEqual } from "crypto";
|
|
19
|
+
import QRCode from "qrcode";
|
|
20
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
21
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
22
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
23
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
24
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
25
|
+
}
|
|
26
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
27
|
+
function _ts_metadata(k, v) {
|
|
28
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
29
|
+
}
|
|
30
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
31
|
+
function _ts_param(paramIndex, decorator) {
|
|
32
|
+
return function(target, key) {
|
|
33
|
+
decorator(target, key, paramIndex);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
__name(_ts_param, "_ts_param");
|
|
37
|
+
var GENERATED_PASSWORD_BYTES = 12;
|
|
38
|
+
function timingSafeEqualStr(a, b) {
|
|
39
|
+
const ab = Buffer.from(a, "utf8");
|
|
40
|
+
const bb = Buffer.from(b, "utf8");
|
|
41
|
+
if (ab.length !== bb.length) return false;
|
|
42
|
+
return timingSafeEqual(ab, bb);
|
|
43
|
+
}
|
|
44
|
+
__name(timingSafeEqualStr, "timingSafeEqualStr");
|
|
45
|
+
var SetupService = class {
|
|
46
|
+
static {
|
|
47
|
+
__name(this, "SetupService");
|
|
48
|
+
}
|
|
49
|
+
users;
|
|
50
|
+
config;
|
|
51
|
+
mfa;
|
|
52
|
+
constructor(users, config, mfa) {
|
|
53
|
+
this.users = users;
|
|
54
|
+
this.config = config;
|
|
55
|
+
this.mfa = mfa;
|
|
56
|
+
}
|
|
57
|
+
async status() {
|
|
58
|
+
return {
|
|
59
|
+
needsSetup: await this.users.countSuperAdmins() === 0
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async setup(req) {
|
|
63
|
+
this.assertToken(req.token);
|
|
64
|
+
await this.assertNoSuperAdmin();
|
|
65
|
+
const email = req.email.trim().toLowerCase();
|
|
66
|
+
if (!email.includes("@")) {
|
|
67
|
+
throw new BadRequestException({
|
|
68
|
+
code: SETUP_ERROR_CODES.INVALID_EMAIL
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const generated = !req.password;
|
|
72
|
+
const password = req.password ?? randomBytes(GENERATED_PASSWORD_BYTES).toString("base64url");
|
|
73
|
+
let user;
|
|
74
|
+
try {
|
|
75
|
+
user = await this.users.createSuperAdmin({
|
|
76
|
+
email,
|
|
77
|
+
password
|
|
78
|
+
});
|
|
79
|
+
} catch (err) {
|
|
80
|
+
if (isPlatformUserExistsError(err)) {
|
|
81
|
+
throw new ConflictException({
|
|
82
|
+
code: SETUP_ERROR_CODES.EMAIL_EXISTS,
|
|
83
|
+
message: err.message
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
const totp = await this.mfa.setup(user.id, user.email, this.config.mfaIssuer);
|
|
89
|
+
const qrDataUrl = await QRCode.toDataURL(totp.otpauthUri, {
|
|
90
|
+
width: 220,
|
|
91
|
+
margin: 1
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
userId: user.id,
|
|
95
|
+
email: user.email,
|
|
96
|
+
otpauthUri: totp.otpauthUri,
|
|
97
|
+
qrDataUrl,
|
|
98
|
+
secret: totp.secret,
|
|
99
|
+
...generated ? {
|
|
100
|
+
generatedPassword: password
|
|
101
|
+
} : {}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async confirmMfa(req) {
|
|
105
|
+
this.assertToken(req.token);
|
|
106
|
+
const ok = await this.mfa.verify({
|
|
107
|
+
userId: req.userId,
|
|
108
|
+
code: req.code
|
|
109
|
+
});
|
|
110
|
+
return {
|
|
111
|
+
ok
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
assertToken(token) {
|
|
115
|
+
const expected = process.env[this.config.setupTokenEnvVar]?.trim();
|
|
116
|
+
if (!expected) {
|
|
117
|
+
throw new ForbiddenException({
|
|
118
|
+
code: SETUP_ERROR_CODES.SETUP_DISABLED,
|
|
119
|
+
message: `${this.config.setupTokenEnvVar} ist nicht gesetzt \u2014 Setup ist deaktiviert.`
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (!token || !timingSafeEqualStr(token, expected)) {
|
|
123
|
+
throw new UnauthorizedException({
|
|
124
|
+
code: SETUP_ERROR_CODES.INVALID_SETUP_TOKEN
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async assertNoSuperAdmin() {
|
|
129
|
+
if (await this.users.countSuperAdmins() > 0) {
|
|
130
|
+
throw new ConflictException({
|
|
131
|
+
code: SETUP_ERROR_CODES.SETUP_ALREADY_DONE
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
SetupService = _ts_decorate([
|
|
137
|
+
Injectable(),
|
|
138
|
+
_ts_param(0, Inject(SETUP_PROVISIONING_PORT_TOKEN)),
|
|
139
|
+
_ts_param(1, Inject(SETUP_CONFIG_TOKEN)),
|
|
140
|
+
_ts_metadata("design:type", Function),
|
|
141
|
+
_ts_metadata("design:paramtypes", [
|
|
142
|
+
typeof SuperAdminProvisioningPort === "undefined" ? Object : SuperAdminProvisioningPort,
|
|
143
|
+
typeof SetupConfig === "undefined" ? Object : SetupConfig,
|
|
144
|
+
typeof MfaService === "undefined" ? Object : MfaService
|
|
145
|
+
])
|
|
146
|
+
], SetupService);
|
|
147
|
+
|
|
148
|
+
// src/setup/setup.controller.ts
|
|
149
|
+
import { Body, Controller, Get, Post } from "@nestjs/common";
|
|
150
|
+
import { IsEmail, IsNotEmpty, IsOptional, IsString, MinLength } from "class-validator";
|
|
151
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
152
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
153
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
154
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
155
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
156
|
+
}
|
|
157
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
158
|
+
function _ts_metadata2(k, v) {
|
|
159
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
160
|
+
}
|
|
161
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
162
|
+
function _ts_param2(paramIndex, decorator) {
|
|
163
|
+
return function(target, key) {
|
|
164
|
+
decorator(target, key, paramIndex);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
__name(_ts_param2, "_ts_param");
|
|
168
|
+
var SetupDto = class SetupDto2 {
|
|
169
|
+
static {
|
|
170
|
+
__name(this, "SetupDto");
|
|
171
|
+
}
|
|
172
|
+
token;
|
|
173
|
+
email;
|
|
174
|
+
password;
|
|
175
|
+
};
|
|
176
|
+
_ts_decorate2([
|
|
177
|
+
IsString(),
|
|
178
|
+
IsNotEmpty(),
|
|
179
|
+
_ts_metadata2("design:type", String)
|
|
180
|
+
], SetupDto.prototype, "token", void 0);
|
|
181
|
+
_ts_decorate2([
|
|
182
|
+
IsEmail(),
|
|
183
|
+
_ts_metadata2("design:type", String)
|
|
184
|
+
], SetupDto.prototype, "email", void 0);
|
|
185
|
+
_ts_decorate2([
|
|
186
|
+
IsOptional(),
|
|
187
|
+
IsString(),
|
|
188
|
+
MinLength(8),
|
|
189
|
+
_ts_metadata2("design:type", String)
|
|
190
|
+
], SetupDto.prototype, "password", void 0);
|
|
191
|
+
var SetupConfirmMfaDto = class SetupConfirmMfaDto2 {
|
|
192
|
+
static {
|
|
193
|
+
__name(this, "SetupConfirmMfaDto");
|
|
194
|
+
}
|
|
195
|
+
token;
|
|
196
|
+
userId;
|
|
197
|
+
code;
|
|
198
|
+
};
|
|
199
|
+
_ts_decorate2([
|
|
200
|
+
IsString(),
|
|
201
|
+
IsNotEmpty(),
|
|
202
|
+
_ts_metadata2("design:type", String)
|
|
203
|
+
], SetupConfirmMfaDto.prototype, "token", void 0);
|
|
204
|
+
_ts_decorate2([
|
|
205
|
+
IsString(),
|
|
206
|
+
IsNotEmpty(),
|
|
207
|
+
_ts_metadata2("design:type", String)
|
|
208
|
+
], SetupConfirmMfaDto.prototype, "userId", void 0);
|
|
209
|
+
_ts_decorate2([
|
|
210
|
+
IsString(),
|
|
211
|
+
IsNotEmpty(),
|
|
212
|
+
_ts_metadata2("design:type", String)
|
|
213
|
+
], SetupConfirmMfaDto.prototype, "code", void 0);
|
|
214
|
+
var SetupController = class {
|
|
215
|
+
static {
|
|
216
|
+
__name(this, "SetupController");
|
|
217
|
+
}
|
|
218
|
+
setup;
|
|
219
|
+
constructor(setup) {
|
|
220
|
+
this.setup = setup;
|
|
221
|
+
}
|
|
222
|
+
status() {
|
|
223
|
+
return this.setup.status();
|
|
224
|
+
}
|
|
225
|
+
run(dto) {
|
|
226
|
+
return this.setup.setup(dto);
|
|
227
|
+
}
|
|
228
|
+
confirm(dto) {
|
|
229
|
+
return this.setup.confirmMfa(dto);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
_ts_decorate2([
|
|
233
|
+
Get("status"),
|
|
234
|
+
_ts_metadata2("design:type", Function),
|
|
235
|
+
_ts_metadata2("design:paramtypes", []),
|
|
236
|
+
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
237
|
+
], SetupController.prototype, "status", null);
|
|
238
|
+
_ts_decorate2([
|
|
239
|
+
Post(),
|
|
240
|
+
_ts_param2(0, Body()),
|
|
241
|
+
_ts_metadata2("design:type", Function),
|
|
242
|
+
_ts_metadata2("design:paramtypes", [
|
|
243
|
+
typeof SetupDto === "undefined" ? Object : SetupDto
|
|
244
|
+
]),
|
|
245
|
+
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
246
|
+
], SetupController.prototype, "run", null);
|
|
247
|
+
_ts_decorate2([
|
|
248
|
+
Post("confirm-mfa"),
|
|
249
|
+
_ts_param2(0, Body()),
|
|
250
|
+
_ts_metadata2("design:type", Function),
|
|
251
|
+
_ts_metadata2("design:paramtypes", [
|
|
252
|
+
typeof SetupConfirmMfaDto === "undefined" ? Object : SetupConfirmMfaDto
|
|
253
|
+
]),
|
|
254
|
+
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
255
|
+
], SetupController.prototype, "confirm", null);
|
|
256
|
+
SetupController = _ts_decorate2([
|
|
257
|
+
Controller("admin/setup"),
|
|
258
|
+
_ts_metadata2("design:type", Function),
|
|
259
|
+
_ts_metadata2("design:paramtypes", [
|
|
260
|
+
typeof SetupService === "undefined" ? Object : SetupService
|
|
261
|
+
])
|
|
262
|
+
], SetupController);
|
|
263
|
+
|
|
264
|
+
// src/setup/setup.module.ts
|
|
265
|
+
import { Module } from "@nestjs/common";
|
|
266
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
267
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
268
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
269
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
270
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
271
|
+
}
|
|
272
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
273
|
+
var DEFAULT_SETUP_TOKEN_ENV_VAR = "SETUP_TOKEN";
|
|
274
|
+
var DEFAULT_MFA_ISSUER = "SuperAdmin";
|
|
275
|
+
var SetupModule = class _SetupModule {
|
|
276
|
+
static {
|
|
277
|
+
__name(this, "SetupModule");
|
|
278
|
+
}
|
|
279
|
+
static forRoot(options) {
|
|
280
|
+
return {
|
|
281
|
+
module: _SetupModule,
|
|
282
|
+
global: options.global ?? false,
|
|
283
|
+
controllers: [
|
|
284
|
+
SetupController
|
|
285
|
+
],
|
|
286
|
+
providers: [
|
|
287
|
+
asProvider(SETUP_PROVISIONING_PORT_TOKEN, options.provisioningPort),
|
|
288
|
+
{
|
|
289
|
+
provide: SETUP_CONFIG_TOKEN,
|
|
290
|
+
useValue: {
|
|
291
|
+
setupTokenEnvVar: options.setupTokenEnvVar ?? DEFAULT_SETUP_TOKEN_ENV_VAR,
|
|
292
|
+
mfaIssuer: options.mfaIssuer ?? DEFAULT_MFA_ISSUER
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
SetupService
|
|
296
|
+
],
|
|
297
|
+
exports: [
|
|
298
|
+
SetupService
|
|
299
|
+
]
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
SetupModule = _ts_decorate3([
|
|
304
|
+
Module({})
|
|
305
|
+
], SetupModule);
|
|
306
|
+
|
|
307
|
+
export {
|
|
308
|
+
SETUP_PROVISIONING_PORT_TOKEN,
|
|
309
|
+
SETUP_CONFIG_TOKEN,
|
|
310
|
+
SetupService,
|
|
311
|
+
SetupController,
|
|
312
|
+
SetupModule
|
|
313
|
+
};
|
|
@@ -34,8 +34,8 @@ var DEFAULT_APP_INFO = {
|
|
|
34
34
|
key: "unknown",
|
|
35
35
|
version: "0.0.0"
|
|
36
36
|
};
|
|
37
|
-
var DISCOVERY_APP_INFO_TOKEN = /* @__PURE__ */ Symbol("
|
|
38
|
-
var DISCOVERY_SNAPSHOT_PATH_TOKEN = /* @__PURE__ */ Symbol("
|
|
37
|
+
var DISCOVERY_APP_INFO_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/DiscoveryAppInfo");
|
|
38
|
+
var DISCOVERY_SNAPSHOT_PATH_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/DiscoverySnapshotPath");
|
|
39
39
|
var DiscoveryScanner = class _DiscoveryScanner {
|
|
40
40
|
static {
|
|
41
41
|
__name(this, "DiscoveryScanner");
|