@tellescope/sdk 1.256.13 → 1.256.14
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/lib/cjs/tests/api_tests/organization_signup.test.d.ts +20 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.js +272 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +336 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +354 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +389 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +324 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +282 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js +329 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
- package/lib/cjs/tests/setup_isolated.d.ts +68 -0
- package/lib/cjs/tests/setup_isolated.d.ts.map +1 -0
- package/lib/cjs/tests/setup_isolated.js +232 -0
- package/lib/cjs/tests/setup_isolated.js.map +1 -0
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +257 -209
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.js +89 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.js.map +1 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js +140 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
- package/lib/esm/enduser.d.ts +1 -0
- package/lib/esm/enduser.d.ts.map +1 -1
- package/lib/esm/sdk.d.ts +3 -2
- package/lib/esm/sdk.d.ts.map +1 -1
- package/lib/esm/session.d.ts +1 -0
- package/lib/esm/session.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/organization_signup.test.d.ts +20 -0
- package/lib/esm/tests/api_tests/organization_signup.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/organization_signup.test.js +264 -0
- package/lib/esm/tests/api_tests/organization_signup.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +332 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +350 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +382 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +317 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +277 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js +324 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
- package/lib/esm/tests/setup_isolated.d.ts +68 -0
- package/lib/esm/tests/setup_isolated.d.ts.map +1 -0
- package/lib/esm/tests/setup_isolated.js +221 -0
- package/lib/esm/tests/setup_isolated.js.map +1 -0
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +257 -209
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.js +85 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.js.map +1 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js +113 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/tests/api_tests/organization_signup.test.ts +240 -0
- package/src/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.ts +225 -0
- package/src/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.ts +162 -0
- package/src/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.ts +288 -0
- package/src/tests/api_tests/security/F-0192-automated-actions-process-gate.test.ts +238 -0
- package/src/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.ts +208 -0
- package/src/tests/api_tests/tickets_bulk_assign_from_queue.test.ts +279 -0
- package/src/tests/setup_isolated.ts +170 -0
- package/src/tests/tests.ts +25 -0
- package/src/tests/unit_tests/do_not_send_address.test.ts +60 -0
- package/src/tests/unit_tests/openapi_spec_freshness.test.ts +88 -0
- package/test_generated.pdf +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Check } from "../setup_isolated";
|
|
2
|
+
/**
|
|
3
|
+
* Covers the self-service organization signup chain, which had ZERO test coverage:
|
|
4
|
+
* `users.register` -> `users.submit_email_verification` -> `organizations.create_and_join`.
|
|
5
|
+
*
|
|
6
|
+
* That gap is why F-0191 nearly shipped a schema `adminOnly` flag on create_and_join that would have
|
|
7
|
+
* 401'd every new organization — a freshly registered user has no `roles`, because create_and_join is
|
|
8
|
+
* itself what grants Admin. This test is the regression guard for that.
|
|
9
|
+
*
|
|
10
|
+
* It also covers the new test-support provisioning module, including the assertion that matters most:
|
|
11
|
+
* teardown refuses any organization it did not create.
|
|
12
|
+
*
|
|
13
|
+
* Uses a `dontsend...@tellescope.com` address so the verification email is dropped at
|
|
14
|
+
* forCommunications before it is ever enqueued (locally the worker consumes the same test queue the
|
|
15
|
+
* API writes to, so an unsuppressed registration really does send mail).
|
|
16
|
+
*/
|
|
17
|
+
export declare const organization_signup_checks: () => Promise<Check[]>;
|
|
18
|
+
/** Asserting wrapper, for standalone runs and for sequential use in the suite. */
|
|
19
|
+
export declare const organization_signup_tests: () => Promise<void>;
|
|
20
|
+
//# sourceMappingURL=organization_signup.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization_signup.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/api_tests/organization_signup.test.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,EAIN,MAAM,mBAAmB,CAAA;AAS1B;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,0BAA0B,QAAa,QAAQ,KAAK,EAAE,CAwLlE,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,qBAErC,CAAA"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.organization_signup_tests = exports.organization_signup_checks = void 0;
|
|
43
|
+
require('source-map-support').install();
|
|
44
|
+
var axios_1 = __importDefault(require("axios"));
|
|
45
|
+
var sdk_1 = require("../../sdk");
|
|
46
|
+
var testing_1 = require("@tellescope/testing");
|
|
47
|
+
var setup_isolated_1 = require("../setup_isolated");
|
|
48
|
+
var host = process.env.API_URL || 'http://localhost:8080';
|
|
49
|
+
var RAND = function () { return Math.random().toString(36).slice(2, 10); };
|
|
50
|
+
// legacy shared fixture — teardown must refuse it
|
|
51
|
+
var SEEDED_TEST_BUSINESS_ID = '60398b1131a295e64f084ff6';
|
|
52
|
+
/**
|
|
53
|
+
* Covers the self-service organization signup chain, which had ZERO test coverage:
|
|
54
|
+
* `users.register` -> `users.submit_email_verification` -> `organizations.create_and_join`.
|
|
55
|
+
*
|
|
56
|
+
* That gap is why F-0191 nearly shipped a schema `adminOnly` flag on create_and_join that would have
|
|
57
|
+
* 401'd every new organization — a freshly registered user has no `roles`, because create_and_join is
|
|
58
|
+
* itself what grants Admin. This test is the regression guard for that.
|
|
59
|
+
*
|
|
60
|
+
* It also covers the new test-support provisioning module, including the assertion that matters most:
|
|
61
|
+
* teardown refuses any organization it did not create.
|
|
62
|
+
*
|
|
63
|
+
* Uses a `dontsend...@tellescope.com` address so the verification email is dropped at
|
|
64
|
+
* forCommunications before it is ever enqueued (locally the worker consumes the same test queue the
|
|
65
|
+
* API writes to, so an unsuppressed registration really does send mail).
|
|
66
|
+
*/
|
|
67
|
+
var organization_signup_checks = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
68
|
+
var checks, record, bootstrapUserId, createdBusinessId, provisioned, keyDetail, keyPass, keySession, e_1, enduser, refusal, email, password, registerResult, preVerifyLogin, unverifiedAttempt, code, verified, subdomain, joined, second, disposable, disposableKey, secondTeardown, revokedDetail, revokedPass, e_2, e_3, _a;
|
|
69
|
+
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11;
|
|
70
|
+
return __generator(this, function (_12) {
|
|
71
|
+
switch (_12.label) {
|
|
72
|
+
case 0:
|
|
73
|
+
checks = [];
|
|
74
|
+
record = function (label, pass, detail) { return checks.push({ label: label, pass: pass, detail: detail }); };
|
|
75
|
+
bootstrapUserId = '';
|
|
76
|
+
createdBusinessId = '';
|
|
77
|
+
_12.label = 1;
|
|
78
|
+
case 1:
|
|
79
|
+
_12.trys.push([1, , 25, 34]);
|
|
80
|
+
return [4 /*yield*/, (0, setup_isolated_1.setup_isolated_tenant)()];
|
|
81
|
+
case 2:
|
|
82
|
+
/* ===== A: provisioning works with no seeded database ===== */
|
|
83
|
+
provisioned = _12.sent();
|
|
84
|
+
record('A1: provision-tenant returns a usable admin session', !!provisioned.businessId && ((_b = provisioned.sdk.userInfo) === null || _b === void 0 ? void 0 : _b.businessId) === provisioned.businessId, "businessId=".concat(provisioned.businessId, " session businessId=").concat((_c = provisioned.sdk.userInfo) === null || _c === void 0 ? void 0 : _c.businessId));
|
|
85
|
+
keyDetail = '';
|
|
86
|
+
keyPass = false;
|
|
87
|
+
_12.label = 3;
|
|
88
|
+
case 3:
|
|
89
|
+
_12.trys.push([3, 5, , 6]);
|
|
90
|
+
keySession = new sdk_1.Session({ host: host, apiKey: provisioned.apiKeys[0] });
|
|
91
|
+
return [4 /*yield*/, keySession.test_authenticated()];
|
|
92
|
+
case 4:
|
|
93
|
+
keyDetail = _12.sent();
|
|
94
|
+
keyPass = keyDetail === 'Authenticated!';
|
|
95
|
+
return [3 /*break*/, 6];
|
|
96
|
+
case 5:
|
|
97
|
+
e_1 = _12.sent();
|
|
98
|
+
keyDetail = "rejected: ".concat((e_1 === null || e_1 === void 0 ? void 0 : e_1.message) || (e_1 === null || e_1 === void 0 ? void 0 : e_1.toString()));
|
|
99
|
+
return [3 /*break*/, 6];
|
|
100
|
+
case 6:
|
|
101
|
+
record('A2: a provisioned API key authenticates', keyPass, "test_authenticated -> ".concat(keyDetail));
|
|
102
|
+
return [4 /*yield*/, provisioned.sdk.api.endusers.createOne({ fname: 'Provisioned', lname: 'Patient' })];
|
|
103
|
+
case 7:
|
|
104
|
+
enduser = _12.sent();
|
|
105
|
+
record('A3: the provisioned tenant accepts writes', !!enduser.id, "enduserId=".concat(enduser.id));
|
|
106
|
+
return [4 /*yield*/, (0, setup_isolated_1.test_support_request)('/teardown-tenant', { businessId: SEEDED_TEST_BUSINESS_ID })];
|
|
107
|
+
case 8:
|
|
108
|
+
refusal = _12.sent();
|
|
109
|
+
record('B1: teardown REFUSES an organization without the provenance marker', refusal.status === 403, "status=".concat(refusal.status, " ").concat(JSON.stringify(refusal.body), " (expected 403)"));
|
|
110
|
+
email = "dontsend-signup-".concat(RAND(), "@tellescope.com");
|
|
111
|
+
password = "Signup-".concat(RAND(), "-A1!");
|
|
112
|
+
return [4 /*yield*/, axios_1.default.request({
|
|
113
|
+
method: 'post', url: "".concat(host, "/v1/users/register"),
|
|
114
|
+
data: { email: email, password: password, termsVersion: '1' },
|
|
115
|
+
validateStatus: function () { return true; },
|
|
116
|
+
})];
|
|
117
|
+
case 9:
|
|
118
|
+
registerResult = _12.sent();
|
|
119
|
+
record('C1: register accepts a new org-less user', registerResult.status === 204, "status=".concat(registerResult.status, " ").concat(JSON.stringify((_d = registerResult.data) !== null && _d !== void 0 ? _d : '')));
|
|
120
|
+
return [4 /*yield*/, (0, testing_1.wait)(undefined, 1200)
|
|
121
|
+
// login works before verification, which is how a test learns the new user's id
|
|
122
|
+
]; // register is IP-limited to ~1/sec
|
|
123
|
+
case 10:
|
|
124
|
+
_12.sent(); // register is IP-limited to ~1/sec
|
|
125
|
+
return [4 /*yield*/, axios_1.default.request({
|
|
126
|
+
method: 'post', url: "".concat(host, "/v1/users/login"),
|
|
127
|
+
data: { email: email, password: password },
|
|
128
|
+
validateStatus: function () { return true; },
|
|
129
|
+
})];
|
|
130
|
+
case 11:
|
|
131
|
+
preVerifyLogin = _12.sent();
|
|
132
|
+
bootstrapUserId = (_g = (_f = (_e = preVerifyLogin.data) === null || _e === void 0 ? void 0 : _e.user) === null || _f === void 0 ? void 0 : _f.id) !== null && _g !== void 0 ? _g : '';
|
|
133
|
+
record('C2: the unverified user can log in (and is org-less)', preVerifyLogin.status === 200 && !!bootstrapUserId && !((_j = (_h = preVerifyLogin.data) === null || _h === void 0 ? void 0 : _h.user) === null || _j === void 0 ? void 0 : _j.businessId), "status=".concat(preVerifyLogin.status, " id=").concat(bootstrapUserId, " businessId=").concat((_m = (_l = (_k = preVerifyLogin.data) === null || _k === void 0 ? void 0 : _k.user) === null || _l === void 0 ? void 0 : _l.businessId) !== null && _m !== void 0 ? _m : '(none)'));
|
|
134
|
+
return [4 /*yield*/, axios_1.default.request({
|
|
135
|
+
method: 'post', url: "".concat(host, "/v1/organizations/create-and-join"),
|
|
136
|
+
data: { name: 'Should Not Work', subdomain: "nope-".concat(RAND()) },
|
|
137
|
+
headers: { Authorization: "Bearer ".concat((_o = preVerifyLogin.data) === null || _o === void 0 ? void 0 : _o.authToken) },
|
|
138
|
+
validateStatus: function () { return true; },
|
|
139
|
+
})];
|
|
140
|
+
case 12:
|
|
141
|
+
unverifiedAttempt = _12.sent();
|
|
142
|
+
record('C3: create_and_join is rejected before email verification', unverifiedAttempt.status === 400, "status=".concat(unverifiedAttempt.status, " ").concat(JSON.stringify((_p = unverifiedAttempt.data) !== null && _p !== void 0 ? _p : '')));
|
|
143
|
+
code = "verify-".concat(RAND());
|
|
144
|
+
return [4 /*yield*/, (0, setup_isolated_1.set_email_verification_code)(email, code)];
|
|
145
|
+
case 13:
|
|
146
|
+
_12.sent();
|
|
147
|
+
return [4 /*yield*/, axios_1.default.request({
|
|
148
|
+
method: 'post', url: "".concat(host, "/v1/users/submit-email-verification"),
|
|
149
|
+
data: { email: email, code: code },
|
|
150
|
+
validateStatus: function () { return true; },
|
|
151
|
+
})];
|
|
152
|
+
case 14:
|
|
153
|
+
verified = _12.sent();
|
|
154
|
+
record('C4: submit_email_verification accepts the code and mints a token', verified.status === 200 && !!((_q = verified.data) === null || _q === void 0 ? void 0 : _q.authToken), "status=".concat(verified.status, " authToken=").concat(!!((_r = verified.data) === null || _r === void 0 ? void 0 : _r.authToken)));
|
|
155
|
+
subdomain = "signup-".concat(RAND());
|
|
156
|
+
return [4 /*yield*/, axios_1.default.request({
|
|
157
|
+
method: 'post', url: "".concat(host, "/v1/organizations/create-and-join"),
|
|
158
|
+
data: { name: "Signup Test ".concat(RAND()), subdomain: subdomain },
|
|
159
|
+
headers: { Authorization: "Bearer ".concat((_s = verified.data) === null || _s === void 0 ? void 0 : _s.authToken) },
|
|
160
|
+
validateStatus: function () { return true; },
|
|
161
|
+
})];
|
|
162
|
+
case 15:
|
|
163
|
+
joined = _12.sent();
|
|
164
|
+
createdBusinessId = (_v = (_u = (_t = joined.data) === null || _t === void 0 ? void 0 : _t.organization) === null || _u === void 0 ? void 0 : _u.id) !== null && _v !== void 0 ? _v : '';
|
|
165
|
+
record('D1: a freshly verified, org-less user can create and join an organization', joined.status === 200 && !!createdBusinessId, "status=".concat(joined.status, " organizationId=").concat(createdBusinessId, " ").concat(joined.status !== 200 ? JSON.stringify(joined.data) : ''));
|
|
166
|
+
record('D2: the handler grants Admin and sets businessId (the roles bootstrap)', ((_y = (_x = (_w = joined.data) === null || _w === void 0 ? void 0 : _w.user) === null || _x === void 0 ? void 0 : _x.roles) === null || _y === void 0 ? void 0 : _y.includes('Admin')) && ((_0 = (_z = joined.data) === null || _z === void 0 ? void 0 : _z.user) === null || _0 === void 0 ? void 0 : _0.businessId) === createdBusinessId, "roles=".concat(JSON.stringify((_2 = (_1 = joined.data) === null || _1 === void 0 ? void 0 : _1.user) === null || _2 === void 0 ? void 0 : _2.roles), " businessId=").concat((_4 = (_3 = joined.data) === null || _3 === void 0 ? void 0 : _3.user) === null || _4 === void 0 ? void 0 : _4.businessId));
|
|
167
|
+
record('D3: a fresh token is returned', !!((_5 = joined.data) === null || _5 === void 0 ? void 0 : _5.authToken) && joined.data.authToken !== ((_6 = verified.data) === null || _6 === void 0 ? void 0 : _6.authToken), "token returned=".concat(!!((_7 = joined.data) === null || _7 === void 0 ? void 0 : _7.authToken), ", rotated=").concat(((_8 = joined.data) === null || _8 === void 0 ? void 0 : _8.authToken) !== ((_9 = verified.data) === null || _9 === void 0 ? void 0 : _9.authToken)));
|
|
168
|
+
return [4 /*yield*/, axios_1.default.request({
|
|
169
|
+
method: 'post', url: "".concat(host, "/v1/organizations/create-and-join"),
|
|
170
|
+
data: { name: 'Second Org', subdomain: "signup-".concat(RAND()) },
|
|
171
|
+
headers: { Authorization: "Bearer ".concat((_10 = joined.data) === null || _10 === void 0 ? void 0 : _10.authToken) },
|
|
172
|
+
validateStatus: function () { return true; },
|
|
173
|
+
})];
|
|
174
|
+
case 16:
|
|
175
|
+
second = _12.sent();
|
|
176
|
+
record('D4: a user already in an organization cannot create another', second.status === 400, "status=".concat(second.status, " ").concat(JSON.stringify((_11 = second.data) !== null && _11 !== void 0 ? _11 : '')));
|
|
177
|
+
return [4 /*yield*/, (0, setup_isolated_1.setup_isolated_tenant)({ users: [{ isAdmin: true }], apiKeys: 1 })];
|
|
178
|
+
case 17:
|
|
179
|
+
disposable = _12.sent();
|
|
180
|
+
disposableKey = disposable.apiKeys[0];
|
|
181
|
+
return [4 /*yield*/, disposable.sdk.api.endusers.createOne({ fname: 'Disposable', lname: 'Patient' })];
|
|
182
|
+
case 18:
|
|
183
|
+
_12.sent();
|
|
184
|
+
return [4 /*yield*/, disposable.teardown()];
|
|
185
|
+
case 19:
|
|
186
|
+
_12.sent();
|
|
187
|
+
return [4 /*yield*/, (0, setup_isolated_1.test_support_request)('/teardown-tenant', { businessId: disposable.businessId })];
|
|
188
|
+
case 20:
|
|
189
|
+
secondTeardown = _12.sent();
|
|
190
|
+
record('E1: teardown removes the organization record itself', secondTeardown.status === 404, "re-teardown status=".concat(secondTeardown.status, " ").concat(JSON.stringify(secondTeardown.body), " (expected 404 \u2014 org gone)"));
|
|
191
|
+
revokedDetail = '';
|
|
192
|
+
revokedPass = false;
|
|
193
|
+
_12.label = 21;
|
|
194
|
+
case 21:
|
|
195
|
+
_12.trys.push([21, 23, , 24]);
|
|
196
|
+
return [4 /*yield*/, (new sdk_1.Session({ host: host, apiKey: disposableKey })).test_authenticated()];
|
|
197
|
+
case 22:
|
|
198
|
+
revokedDetail = _12.sent();
|
|
199
|
+
return [3 /*break*/, 24];
|
|
200
|
+
case 23:
|
|
201
|
+
e_2 = _12.sent();
|
|
202
|
+
revokedPass = true;
|
|
203
|
+
revokedDetail = "rejected: ".concat((e_2 === null || e_2 === void 0 ? void 0 : e_2.message) || (e_2 === null || e_2 === void 0 ? void 0 : e_2.toString()));
|
|
204
|
+
return [3 /*break*/, 24];
|
|
205
|
+
case 24:
|
|
206
|
+
record('E2: the torn-down tenant\'s API key no longer authenticates', revokedPass, revokedDetail);
|
|
207
|
+
return [3 /*break*/, 34];
|
|
208
|
+
case 25:
|
|
209
|
+
if (!provisioned) return [3 /*break*/, 29];
|
|
210
|
+
_12.label = 26;
|
|
211
|
+
case 26:
|
|
212
|
+
_12.trys.push([26, 28, , 29]);
|
|
213
|
+
return [4 /*yield*/, provisioned.teardown()];
|
|
214
|
+
case 27:
|
|
215
|
+
_12.sent();
|
|
216
|
+
return [3 /*break*/, 29];
|
|
217
|
+
case 28:
|
|
218
|
+
e_3 = _12.sent();
|
|
219
|
+
console.error('teardown failed', e_3);
|
|
220
|
+
return [3 /*break*/, 29];
|
|
221
|
+
case 29:
|
|
222
|
+
if (!bootstrapUserId) return [3 /*break*/, 33];
|
|
223
|
+
_12.label = 30;
|
|
224
|
+
case 30:
|
|
225
|
+
_12.trys.push([30, 32, , 33]);
|
|
226
|
+
return [4 /*yield*/, (0, setup_isolated_1.test_support_request)('/delete-user', { userId: bootstrapUserId })];
|
|
227
|
+
case 31:
|
|
228
|
+
_12.sent();
|
|
229
|
+
return [3 /*break*/, 33];
|
|
230
|
+
case 32:
|
|
231
|
+
_a = _12.sent();
|
|
232
|
+
return [3 /*break*/, 33];
|
|
233
|
+
case 33:
|
|
234
|
+
if (createdBusinessId) {
|
|
235
|
+
console.log(" note: organization ".concat(createdBusinessId, " was created by the signup flow and is left behind (nothing can delete an org record)"));
|
|
236
|
+
}
|
|
237
|
+
return [7 /*endfinally*/];
|
|
238
|
+
case 34: return [2 /*return*/, checks];
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}); };
|
|
242
|
+
exports.organization_signup_checks = organization_signup_checks;
|
|
243
|
+
/** Asserting wrapper, for standalone runs and for sequential use in the suite. */
|
|
244
|
+
var organization_signup_tests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
245
|
+
var _a, _b;
|
|
246
|
+
return __generator(this, function (_c) {
|
|
247
|
+
switch (_c.label) {
|
|
248
|
+
case 0:
|
|
249
|
+
_a = setup_isolated_1.assert_checks;
|
|
250
|
+
_b = ['Organization signup'];
|
|
251
|
+
return [4 /*yield*/, (0, exports.organization_signup_checks)()];
|
|
252
|
+
case 1:
|
|
253
|
+
_a.apply(void 0, _b.concat([_c.sent()]));
|
|
254
|
+
return [2 /*return*/];
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}); };
|
|
258
|
+
exports.organization_signup_tests = organization_signup_tests;
|
|
259
|
+
// Allow running this test file independently
|
|
260
|
+
if (require.main === module) {
|
|
261
|
+
console.log("\uD83C\uDF10 Using API URL: ".concat(host));
|
|
262
|
+
(0, exports.organization_signup_tests)()
|
|
263
|
+
.then(function () {
|
|
264
|
+
console.log("✅ Organization signup test suite completed successfully");
|
|
265
|
+
process.exit(0);
|
|
266
|
+
})
|
|
267
|
+
.catch(function (error) {
|
|
268
|
+
console.error("❌ Organization signup test suite failed:", error);
|
|
269
|
+
process.exit(1);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=organization_signup.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization_signup.test.js","sourceRoot":"","sources":["../../../../src/tests/api_tests/organization_signup.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Session } from "../../../sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Regression test for F-0179
|
|
4
|
+
* (security-audit/findings/F-0179-booking-info-idor-token-mint.md).
|
|
5
|
+
*
|
|
6
|
+
* `form_fields.booking_info` resolved its target patient as
|
|
7
|
+
* `DB.endusers.findById(enduserId || req.session.id)` with no ownership check for enduser
|
|
8
|
+
* sessions. The enduser DB branch builds the endusers collection with `enduserAccess: true`
|
|
9
|
+
* (database.ts), so a FOREIGN in-tenant id resolves — and the handler then writes
|
|
10
|
+
* `enduserFields.state` onto that record and calls `login_enduser` with
|
|
11
|
+
* `sessionScopes: ['appointment-booking']`, returning a live 24h token for the victim inside
|
|
12
|
+
* `bookingURL`. booking_info is enduser-callable AND granted to the 'public-form' scope, so a
|
|
13
|
+
* portal patient or an anonymous form-filler could mint a working session as any co-tenant patient.
|
|
14
|
+
*
|
|
15
|
+
* The fix mirrors `prepare_form_response` (api.ts): reject when an enduser session supplies an
|
|
16
|
+
* `enduserId` other than its own, before the booking-page lookup and before the `state` write.
|
|
17
|
+
*
|
|
18
|
+
* RED (pre-fix): A1 and A2 fail — the exploit returns 200 with a bookingURL whose token decodes to
|
|
19
|
+
* the VICTIM's id, and the victim's `state` is overwritten. B/C (positive controls) pass pre-fix.
|
|
20
|
+
* GREEN (post-fix): all six checks pass.
|
|
21
|
+
*
|
|
22
|
+
* Checks are collected and printed before any assert runs: the testing harness has
|
|
23
|
+
* EXIT_ON_FIRST_ERROR, so asserting inline would kill the process before the evidence table and
|
|
24
|
+
* before `finally` cleanup.
|
|
25
|
+
*/
|
|
26
|
+
export declare const booking_info_idor_tests: ({ sdk }: {
|
|
27
|
+
sdk: Session;
|
|
28
|
+
sdkNonAdmin: Session;
|
|
29
|
+
}) => Promise<void>;
|
|
30
|
+
//# sourceMappingURL=F-0179-booking-info-idor-token-mint.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"F-0179-booking-info-idor-token-mint.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAkB,MAAM,cAAc,CAAA;AAqBtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,uBAAuB;SAA2B,OAAO;iBAAe,OAAO;mBA2J3F,CAAA"}
|