@pipeline-builder/api-core 3.4.83 → 3.4.85
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/constants/http-status.d.ts +0 -4
- package/lib/constants/http-status.js +1 -1
- package/lib/helpers/index.d.ts +1 -0
- package/lib/helpers/index.js +2 -1
- package/lib/helpers/org-hierarchy-http.d.ts +34 -0
- package/lib/helpers/org-hierarchy-http.js +64 -0
- package/lib/middleware/auth.d.ts +37 -5
- package/lib/middleware/auth.js +70 -8
- package/lib/middleware/mongo-sanitize.d.ts +12 -1
- package/lib/middleware/mongo-sanitize.js +48 -18
- package/lib/types/common.d.ts +12 -1
- package/lib/types/common.js +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +2 -1
- package/lib/types/permissions.d.ts +36 -0
- package/lib/types/permissions.js +87 -0
- package/lib/utils/alias-resolver.js +1 -14
- package/lib/utils/params.js +11 -8
- package/lib/validation/ai-schemas.d.ts +0 -6
- package/lib/validation/ai-schemas.js +1 -1
- package/lib/validation/common-schemas.d.ts +0 -8
- package/lib/validation/common-schemas.js +1 -1
- package/lib/validation/message-schemas.d.ts +0 -7
- package/lib/validation/message-schemas.js +1 -1
- package/lib/validation/pipeline-schemas.d.ts +0 -7
- package/lib/validation/pipeline-schemas.js +1 -1
- package/lib/validation/plugin-schemas.d.ts +0 -8
- package/lib/validation/plugin-schemas.js +1 -1
- package/package.json +1 -1
|
@@ -23,4 +23,4 @@ export const HttpStatus = {
|
|
|
23
23
|
SERVICE_UNAVAILABLE: 503,
|
|
24
24
|
GATEWAY_TIMEOUT: 504,
|
|
25
25
|
};
|
|
26
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1zdGF0dXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uc3RhbnRzL2h0dHAtc3RhdHVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxVQUFVLEdBQUc7SUFDeEIsY0FBYztJQUNkLEVBQUUsRUFBRSxHQUFHO0lBQ1AsT0FBTyxFQUFFLEdBQUc7SUFDWixRQUFRLEVBQUUsR0FBRztJQUNiLFVBQVUsRUFBRSxHQUFHO0lBRWYsb0JBQW9CO0lBQ3BCLFdBQVcsRUFBRSxHQUFHO0lBQ2hCLFlBQVksRUFBRSxHQUFHO0lBQ2pCLFNBQVMsRUFBRSxHQUFHO0lBQ2QsU0FBUyxFQUFFLEdBQUc7SUFDZCxRQUFRLEVBQUUsR0FBRztJQUNiLG9CQUFvQixFQUFFLEdBQUc7SUFDekIsaUJBQWlCLEVBQUUsR0FBRztJQUV0QixvQkFBb0I7SUFDcEIscUJBQXFCLEVBQUUsR0FBRztJQUMxQixXQUFXLEVBQUUsR0FBRztJQUNoQixtQkFBbUIsRUFBRSxHQUFHO0lBQ3hCLGVBQWUsRUFBRSxHQUFHO0NBQ1osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIEhUVFAgc3RhdHVzIGNvZGVzIG9yZ2FuaXplZCBieSBjYXRlZ29yeS5cbiAqL1xuZXhwb3J0IGNvbnN0IEh0dHBTdGF0dXMgPSB7XG4gIC8vIFN1Y2Nlc3MgMnh4XG4gIE9LOiAyMDAsXG4gIENSRUFURUQ6IDIwMSxcbiAgQUNDRVBURUQ6IDIwMixcbiAgTk9fQ09OVEVOVDogMjA0LFxuXG4gIC8vIENsaWVudCBFcnJvcnMgNHh4XG4gIEJBRF9SRVFVRVNUOiA0MDAsXG4gIFVOQVVUSE9SSVpFRDogNDAxLFxuICBGT1JCSURERU46IDQwMyxcbiAgTk9UX0ZPVU5EOiA0MDQsXG4gIENPTkZMSUNUOiA0MDksXG4gIFVOUFJPQ0VTU0FCTEVfRU5USVRZOiA0MjIsXG4gIFRPT19NQU5ZX1JFUVVFU1RTOiA0MjksXG5cbiAgLy8gU2VydmVyIEVycm9ycyA1eHhcbiAgSU5URVJOQUxfU0VSVkVSX0VSUk9SOiA1MDAsXG4gIEJBRF9HQVRFV0FZOiA1MDIsXG4gIFNFUlZJQ0VfVU5BVkFJTEFCTEU6IDUwMyxcbiAgR0FURVdBWV9USU1FT1VUOiA1MDQsXG59IGFzIGNvbnN0O1xuIl19
|
package/lib/helpers/index.d.ts
CHANGED
package/lib/helpers/index.js
CHANGED
|
@@ -4,4 +4,5 @@ export * from './crud-helpers.js';
|
|
|
4
4
|
export * from './access-helpers.js';
|
|
5
5
|
export * from './sse-helpers.js';
|
|
6
6
|
export * from './org-hierarchy.js';
|
|
7
|
-
|
|
7
|
+
export * from './org-hierarchy-http.js';
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyx5QkFBeUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5leHBvcnQgKiBmcm9tICcuL2NydWQtaGVscGVycy5qcyc7XG5leHBvcnQgKiBmcm9tICcuL2FjY2Vzcy1oZWxwZXJzLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vc3NlLWhlbHBlcnMuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9vcmctaGllcmFyY2h5LmpzJztcbmV4cG9ydCAqIGZyb20gJy4vb3JnLWhpZXJhcmNoeS1odHRwLmpzJztcbiJdfQ==
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ServiceConfig } from '../types/common.js';
|
|
2
|
+
/** Options shared by the platform org-hierarchy HTTP lookups. */
|
|
3
|
+
export interface OrgHierarchyHttpOptions {
|
|
4
|
+
/** Platform service host/port (+ optional default timeout) for the client. */
|
|
5
|
+
service: ServiceConfig;
|
|
6
|
+
/** Service name minted into the service-auth JWT `sub` (e.g. 'compliance'). */
|
|
7
|
+
serviceName: string;
|
|
8
|
+
/**
|
|
9
|
+
* Org id embedded in the signed service token's org context. Defaults to the
|
|
10
|
+
* queried `orgId`; pass a system org id for a system-scoped lookup.
|
|
11
|
+
*/
|
|
12
|
+
authOrgId?: string;
|
|
13
|
+
/** Role carried by the service token (default 'member' — least privilege). */
|
|
14
|
+
role?: 'owner' | 'admin' | 'member';
|
|
15
|
+
/** Extra request headers merged after `Authorization` (e.g. `x-org-id`). */
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
/** Per-request timeout override in ms (falls back to the client default). */
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve an org's direct parent id via platform's
|
|
22
|
+
* `GET /organization/:id/parent`. Returns `undefined` for a root org or a
|
|
23
|
+
* non-2xx response. Throws on a transport failure (connection/timeout) so the
|
|
24
|
+
* caller can apply its own fallback.
|
|
25
|
+
*/
|
|
26
|
+
export declare function fetchParentOrgId(orgId: string, opts: OrgHierarchyHttpOptions): Promise<string | undefined>;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve `[self, ...descendantOrgIds]` for an org via platform's
|
|
29
|
+
* `GET /organization/:id/descendants`. Returns the id list only when it is
|
|
30
|
+
* larger than the org itself (a real subtree), else `undefined`; also
|
|
31
|
+
* `undefined` on a non-2xx response. Throws on a transport failure so the
|
|
32
|
+
* caller can apply its own fallback.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fetchOrgDescendants(orgId: string, opts: OrgHierarchyHttpOptions): Promise<string[] | undefined>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Org → team hierarchy lookups over HTTP against the platform service.
|
|
5
|
+
*
|
|
6
|
+
* The Mongoose-based traversal in {@link ./org-hierarchy} is for services that
|
|
7
|
+
* own the org table (platform, quota). Everyone else reads the hierarchy over
|
|
8
|
+
* the wire from platform's authoritative `/organization/:id/*` endpoints. This
|
|
9
|
+
* module centralizes the transport for those reads — URL construction, the
|
|
10
|
+
* signed service-token auth header, and timeout+retry via the shared
|
|
11
|
+
* {@link InternalHttpClient} — so compliance, reporting, and any future caller
|
|
12
|
+
* share ONE mechanism instead of each hand-rolling a `fetch`/client with its
|
|
13
|
+
* own auth and failure semantics.
|
|
14
|
+
*
|
|
15
|
+
* These functions deliberately do NOT swallow transport errors: a connection
|
|
16
|
+
* failure/timeout propagates so each caller keeps its own fallback policy (log
|
|
17
|
+
* level, degrade-to-self vs. return-undefined). A non-2xx response is treated
|
|
18
|
+
* as "no data" (returns undefined), matching what the callers previously did.
|
|
19
|
+
*/
|
|
20
|
+
import { getServiceAuthHeader } from '../middleware/auth.js';
|
|
21
|
+
import { InternalHttpClient } from '../services/http-client.js';
|
|
22
|
+
function buildRequest(orgId, suffix, opts) {
|
|
23
|
+
const client = new InternalHttpClient(opts.service);
|
|
24
|
+
const path = `/organization/${encodeURIComponent(orgId)}/${suffix}`;
|
|
25
|
+
const headers = {
|
|
26
|
+
Authorization: getServiceAuthHeader({
|
|
27
|
+
serviceName: opts.serviceName,
|
|
28
|
+
orgId: opts.authOrgId ?? orgId,
|
|
29
|
+
role: opts.role ?? 'member',
|
|
30
|
+
}),
|
|
31
|
+
...opts.headers,
|
|
32
|
+
};
|
|
33
|
+
return { client, path, headers };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve an org's direct parent id via platform's
|
|
37
|
+
* `GET /organization/:id/parent`. Returns `undefined` for a root org or a
|
|
38
|
+
* non-2xx response. Throws on a transport failure (connection/timeout) so the
|
|
39
|
+
* caller can apply its own fallback.
|
|
40
|
+
*/
|
|
41
|
+
export async function fetchParentOrgId(orgId, opts) {
|
|
42
|
+
const { client, path, headers } = buildRequest(orgId, 'parent', opts);
|
|
43
|
+
const res = await client.get(path, { headers, timeout: opts.timeout });
|
|
44
|
+
if (res.statusCode >= 400)
|
|
45
|
+
return undefined;
|
|
46
|
+
return res.body?.data?.parentOrgId ?? undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve `[self, ...descendantOrgIds]` for an org via platform's
|
|
50
|
+
* `GET /organization/:id/descendants`. Returns the id list only when it is
|
|
51
|
+
* larger than the org itself (a real subtree), else `undefined`; also
|
|
52
|
+
* `undefined` on a non-2xx response. Throws on a transport failure so the
|
|
53
|
+
* caller can apply its own fallback.
|
|
54
|
+
*/
|
|
55
|
+
export async function fetchOrgDescendants(orgId, opts) {
|
|
56
|
+
const { client, path, headers } = buildRequest(orgId, 'descendants', opts);
|
|
57
|
+
const res = await client.get(path, { headers, timeout: opts.timeout });
|
|
58
|
+
if (res.statusCode >= 400)
|
|
59
|
+
return undefined;
|
|
60
|
+
const ids = res.body?.data?.orgIds;
|
|
61
|
+
// Only meaningful when the subtree is larger than the org itself.
|
|
62
|
+
return Array.isArray(ids) && ids.length > 1 ? ids : undefined;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnLWhpZXJhcmNoeS1odHRwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hlbHBlcnMvb3JnLWhpZXJhcmNoeS1odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFFSCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQXNCaEUsU0FBUyxZQUFZLENBQ25CLEtBQWEsRUFDYixNQUFnQyxFQUNoQyxJQUE2QjtJQUU3QixNQUFNLE1BQU0sR0FBRyxJQUFJLGtCQUFrQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNwRCxNQUFNLElBQUksR0FBRyxpQkFBaUIsa0JBQWtCLENBQUMsS0FBSyxDQUFDLElBQUksTUFBTSxFQUFFLENBQUM7SUFDcEUsTUFBTSxPQUFPLEdBQTJCO1FBQ3RDLGFBQWEsRUFBRSxvQkFBb0IsQ0FBQztZQUNsQyxXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDN0IsS0FBSyxFQUFFLElBQUksQ0FBQyxTQUFTLElBQUksS0FBSztZQUM5QixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksSUFBSSxRQUFRO1NBQzVCLENBQUM7UUFDRixHQUFHLElBQUksQ0FBQyxPQUFPO0tBQ2hCLENBQUM7SUFDRixPQUFPLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztBQUNuQyxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGdCQUFnQixDQUFDLEtBQWEsRUFBRSxJQUE2QjtJQUNqRixNQUFNLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsR0FBRyxZQUFZLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN0RSxNQUFNLEdBQUcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxHQUFHLENBQTZDLElBQUksRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDbkgsSUFBSSxHQUFHLENBQUMsVUFBVSxJQUFJLEdBQUc7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUM1QyxPQUFPLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLFdBQVcsSUFBSSxTQUFTLENBQUM7QUFDbEQsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsbUJBQW1CLENBQUMsS0FBYSxFQUFFLElBQTZCO0lBQ3BGLE1BQU0sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxHQUFHLFlBQVksQ0FBQyxLQUFLLEVBQUUsYUFBYSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzNFLE1BQU0sR0FBRyxHQUFHLE1BQU0sTUFBTSxDQUFDLEdBQUcsQ0FBa0MsSUFBSSxFQUFFLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUN4RyxJQUFJLEdBQUcsQ0FBQyxVQUFVLElBQUksR0FBRztRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQzVDLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQztJQUNuQyxrRUFBa0U7SUFDbEUsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBRSxHQUFnQixDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDOUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIE9yZyDihpIgdGVhbSBoaWVyYXJjaHkgbG9va3VwcyBvdmVyIEhUVFAgYWdhaW5zdCB0aGUgcGxhdGZvcm0gc2VydmljZS5cbiAqXG4gKiBUaGUgTW9uZ29vc2UtYmFzZWQgdHJhdmVyc2FsIGluIHtAbGluayAuL29yZy1oaWVyYXJjaHl9IGlzIGZvciBzZXJ2aWNlcyB0aGF0XG4gKiBvd24gdGhlIG9yZyB0YWJsZSAocGxhdGZvcm0sIHF1b3RhKS4gRXZlcnlvbmUgZWxzZSByZWFkcyB0aGUgaGllcmFyY2h5IG92ZXJcbiAqIHRoZSB3aXJlIGZyb20gcGxhdGZvcm0ncyBhdXRob3JpdGF0aXZlIGAvb3JnYW5pemF0aW9uLzppZC8qYCBlbmRwb2ludHMuIFRoaXNcbiAqIG1vZHVsZSBjZW50cmFsaXplcyB0aGUgdHJhbnNwb3J0IGZvciB0aG9zZSByZWFkcyDigJQgVVJMIGNvbnN0cnVjdGlvbiwgdGhlXG4gKiBzaWduZWQgc2VydmljZS10b2tlbiBhdXRoIGhlYWRlciwgYW5kIHRpbWVvdXQrcmV0cnkgdmlhIHRoZSBzaGFyZWRcbiAqIHtAbGluayBJbnRlcm5hbEh0dHBDbGllbnR9IOKAlCBzbyBjb21wbGlhbmNlLCByZXBvcnRpbmcsIGFuZCBhbnkgZnV0dXJlIGNhbGxlclxuICogc2hhcmUgT05FIG1lY2hhbmlzbSBpbnN0ZWFkIG9mIGVhY2ggaGFuZC1yb2xsaW5nIGEgYGZldGNoYC9jbGllbnQgd2l0aCBpdHNcbiAqIG93biBhdXRoIGFuZCBmYWlsdXJlIHNlbWFudGljcy5cbiAqXG4gKiBUaGVzZSBmdW5jdGlvbnMgZGVsaWJlcmF0ZWx5IGRvIE5PVCBzd2FsbG93IHRyYW5zcG9ydCBlcnJvcnM6IGEgY29ubmVjdGlvblxuICogZmFpbHVyZS90aW1lb3V0IHByb3BhZ2F0ZXMgc28gZWFjaCBjYWxsZXIga2VlcHMgaXRzIG93biBmYWxsYmFjayBwb2xpY3kgKGxvZ1xuICogbGV2ZWwsIGRlZ3JhZGUtdG8tc2VsZiB2cy4gcmV0dXJuLXVuZGVmaW5lZCkuIEEgbm9uLTJ4eCByZXNwb25zZSBpcyB0cmVhdGVkXG4gKiBhcyBcIm5vIGRhdGFcIiAocmV0dXJucyB1bmRlZmluZWQpLCBtYXRjaGluZyB3aGF0IHRoZSBjYWxsZXJzIHByZXZpb3VzbHkgZGlkLlxuICovXG5cbmltcG9ydCB7IGdldFNlcnZpY2VBdXRoSGVhZGVyIH0gZnJvbSAnLi4vbWlkZGxld2FyZS9hdXRoLmpzJztcbmltcG9ydCB7IEludGVybmFsSHR0cENsaWVudCB9IGZyb20gJy4uL3NlcnZpY2VzL2h0dHAtY2xpZW50LmpzJztcbmltcG9ydCB0eXBlIHsgU2VydmljZUNvbmZpZyB9IGZyb20gJy4uL3R5cGVzL2NvbW1vbi5qcyc7XG5cbi8qKiBPcHRpb25zIHNoYXJlZCBieSB0aGUgcGxhdGZvcm0gb3JnLWhpZXJhcmNoeSBIVFRQIGxvb2t1cHMuICovXG5leHBvcnQgaW50ZXJmYWNlIE9yZ0hpZXJhcmNoeUh0dHBPcHRpb25zIHtcbiAgLyoqIFBsYXRmb3JtIHNlcnZpY2UgaG9zdC9wb3J0ICgrIG9wdGlvbmFsIGRlZmF1bHQgdGltZW91dCkgZm9yIHRoZSBjbGllbnQuICovXG4gIHNlcnZpY2U6IFNlcnZpY2VDb25maWc7XG4gIC8qKiBTZXJ2aWNlIG5hbWUgbWludGVkIGludG8gdGhlIHNlcnZpY2UtYXV0aCBKV1QgYHN1YmAgKGUuZy4gJ2NvbXBsaWFuY2UnKS4gKi9cbiAgc2VydmljZU5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAqIE9yZyBpZCBlbWJlZGRlZCBpbiB0aGUgc2lnbmVkIHNlcnZpY2UgdG9rZW4ncyBvcmcgY29udGV4dC4gRGVmYXVsdHMgdG8gdGhlXG4gICAqIHF1ZXJpZWQgYG9yZ0lkYDsgcGFzcyBhIHN5c3RlbSBvcmcgaWQgZm9yIGEgc3lzdGVtLXNjb3BlZCBsb29rdXAuXG4gICAqL1xuICBhdXRoT3JnSWQ/OiBzdHJpbmc7XG4gIC8qKiBSb2xlIGNhcnJpZWQgYnkgdGhlIHNlcnZpY2UgdG9rZW4gKGRlZmF1bHQgJ21lbWJlcicg4oCUIGxlYXN0IHByaXZpbGVnZSkuICovXG4gIHJvbGU/OiAnb3duZXInIHwgJ2FkbWluJyB8ICdtZW1iZXInO1xuICAvKiogRXh0cmEgcmVxdWVzdCBoZWFkZXJzIG1lcmdlZCBhZnRlciBgQXV0aG9yaXphdGlvbmAgKGUuZy4gYHgtb3JnLWlkYCkuICovXG4gIGhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAvKiogUGVyLXJlcXVlc3QgdGltZW91dCBvdmVycmlkZSBpbiBtcyAoZmFsbHMgYmFjayB0byB0aGUgY2xpZW50IGRlZmF1bHQpLiAqL1xuICB0aW1lb3V0PzogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBidWlsZFJlcXVlc3QoXG4gIG9yZ0lkOiBzdHJpbmcsXG4gIHN1ZmZpeDogJ3BhcmVudCcgfCAnZGVzY2VuZGFudHMnLFxuICBvcHRzOiBPcmdIaWVyYXJjaHlIdHRwT3B0aW9ucyxcbik6IHsgY2xpZW50OiBJbnRlcm5hbEh0dHBDbGllbnQ7IHBhdGg6IHN0cmluZzsgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB9IHtcbiAgY29uc3QgY2xpZW50ID0gbmV3IEludGVybmFsSHR0cENsaWVudChvcHRzLnNlcnZpY2UpO1xuICBjb25zdCBwYXRoID0gYC9vcmdhbml6YXRpb24vJHtlbmNvZGVVUklDb21wb25lbnQob3JnSWQpfS8ke3N1ZmZpeH1gO1xuICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgIEF1dGhvcml6YXRpb246IGdldFNlcnZpY2VBdXRoSGVhZGVyKHtcbiAgICAgIHNlcnZpY2VOYW1lOiBvcHRzLnNlcnZpY2VOYW1lLFxuICAgICAgb3JnSWQ6IG9wdHMuYXV0aE9yZ0lkID8/IG9yZ0lkLFxuICAgICAgcm9sZTogb3B0cy5yb2xlID8/ICdtZW1iZXInLFxuICAgIH0pLFxuICAgIC4uLm9wdHMuaGVhZGVycyxcbiAgfTtcbiAgcmV0dXJuIHsgY2xpZW50LCBwYXRoLCBoZWFkZXJzIH07XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhbiBvcmcncyBkaXJlY3QgcGFyZW50IGlkIHZpYSBwbGF0Zm9ybSdzXG4gKiBgR0VUIC9vcmdhbml6YXRpb24vOmlkL3BhcmVudGAuIFJldHVybnMgYHVuZGVmaW5lZGAgZm9yIGEgcm9vdCBvcmcgb3IgYVxuICogbm9uLTJ4eCByZXNwb25zZS4gVGhyb3dzIG9uIGEgdHJhbnNwb3J0IGZhaWx1cmUgKGNvbm5lY3Rpb24vdGltZW91dCkgc28gdGhlXG4gKiBjYWxsZXIgY2FuIGFwcGx5IGl0cyBvd24gZmFsbGJhY2suXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaFBhcmVudE9yZ0lkKG9yZ0lkOiBzdHJpbmcsIG9wdHM6IE9yZ0hpZXJhcmNoeUh0dHBPcHRpb25zKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgeyBjbGllbnQsIHBhdGgsIGhlYWRlcnMgfSA9IGJ1aWxkUmVxdWVzdChvcmdJZCwgJ3BhcmVudCcsIG9wdHMpO1xuICBjb25zdCByZXMgPSBhd2FpdCBjbGllbnQuZ2V0PHsgZGF0YT86IHsgcGFyZW50T3JnSWQ/OiBzdHJpbmcgfCBudWxsIH0gfT4ocGF0aCwgeyBoZWFkZXJzLCB0aW1lb3V0OiBvcHRzLnRpbWVvdXQgfSk7XG4gIGlmIChyZXMuc3RhdHVzQ29kZSA+PSA0MDApIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiByZXMuYm9keT8uZGF0YT8ucGFyZW50T3JnSWQgPz8gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYFtzZWxmLCAuLi5kZXNjZW5kYW50T3JnSWRzXWAgZm9yIGFuIG9yZyB2aWEgcGxhdGZvcm0nc1xuICogYEdFVCAvb3JnYW5pemF0aW9uLzppZC9kZXNjZW5kYW50c2AuIFJldHVybnMgdGhlIGlkIGxpc3Qgb25seSB3aGVuIGl0IGlzXG4gKiBsYXJnZXIgdGhhbiB0aGUgb3JnIGl0c2VsZiAoYSByZWFsIHN1YnRyZWUpLCBlbHNlIGB1bmRlZmluZWRgOyBhbHNvXG4gKiBgdW5kZWZpbmVkYCBvbiBhIG5vbi0yeHggcmVzcG9uc2UuIFRocm93cyBvbiBhIHRyYW5zcG9ydCBmYWlsdXJlIHNvIHRoZVxuICogY2FsbGVyIGNhbiBhcHBseSBpdHMgb3duIGZhbGxiYWNrLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2hPcmdEZXNjZW5kYW50cyhvcmdJZDogc3RyaW5nLCBvcHRzOiBPcmdIaWVyYXJjaHlIdHRwT3B0aW9ucyk6IFByb21pc2U8c3RyaW5nW10gfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgeyBjbGllbnQsIHBhdGgsIGhlYWRlcnMgfSA9IGJ1aWxkUmVxdWVzdChvcmdJZCwgJ2Rlc2NlbmRhbnRzJywgb3B0cyk7XG4gIGNvbnN0IHJlcyA9IGF3YWl0IGNsaWVudC5nZXQ8eyBkYXRhPzogeyBvcmdJZHM/OiB1bmtub3duIH0gfT4ocGF0aCwgeyBoZWFkZXJzLCB0aW1lb3V0OiBvcHRzLnRpbWVvdXQgfSk7XG4gIGlmIChyZXMuc3RhdHVzQ29kZSA+PSA0MDApIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IGlkcyA9IHJlcy5ib2R5Py5kYXRhPy5vcmdJZHM7XG4gIC8vIE9ubHkgbWVhbmluZ2Z1bCB3aGVuIHRoZSBzdWJ0cmVlIGlzIGxhcmdlciB0aGFuIHRoZSBvcmcgaXRzZWxmLlxuICByZXR1cm4gQXJyYXkuaXNBcnJheShpZHMpICYmIGlkcy5sZW5ndGggPiAxID8gKGlkcyBhcyBzdHJpbmdbXSkgOiB1bmRlZmluZWQ7XG59XG4iXX0=
|
package/lib/middleware/auth.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { type Permission } from '../types/permissions.js';
|
|
2
3
|
export interface RequireAuthOptions {
|
|
3
4
|
/**
|
|
4
5
|
* Allow x-org-id/x-org-name headers to override the JWT's organization fields.
|
|
@@ -19,13 +20,34 @@ export declare function requireAuth(options?: RequireAuthOptions): (req: Request
|
|
|
19
20
|
* Permits users whose per-org role is 'admin' or 'owner'.
|
|
20
21
|
*/
|
|
21
22
|
export declare function requireAdmin(req: Request, res: Response, next: NextFunction): void;
|
|
22
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Whether the request's user holds `permission`. Superadmins implicitly hold
|
|
25
|
+
* every permission. Reads the resolved `permissions` claim (set at token issue,
|
|
26
|
+
* or re-derived per request by the platform).
|
|
27
|
+
*/
|
|
28
|
+
export declare function userHasPermission(req: Request, permission: Permission): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Requires that the user hold AT LEAST ONE of the given permissions (or be a
|
|
31
|
+
* superadmin). Use after requireAuth. Mirrors `requireRole`'s any-of semantics;
|
|
32
|
+
* pass a single permission for a specific action, or several when any one of
|
|
33
|
+
* them should grant access.
|
|
34
|
+
*/
|
|
35
|
+
export declare function requirePermission(...permissions: Permission[]): (req: Request, res: Response, next: NextFunction) => void;
|
|
36
|
+
/**
|
|
37
|
+
* The system tenant's canonical org **id** — a fixed, well-known ObjectId (NOT
|
|
38
|
+
* the string 'system'). This is the single knob every service resolves the
|
|
39
|
+
* system tenant through; override via the `SYSTEM_ORG_ID` env for alternate
|
|
40
|
+
* installs. The system org's human identifier stays the slug/name 'system'
|
|
41
|
+
* (see {@link SYSTEM_ORG_SLUG}); only its `_id` is this ObjectId.
|
|
42
|
+
*/
|
|
23
43
|
export declare const SYSTEM_ORG_ID: string;
|
|
44
|
+
/** The system org's well-known slug/name (the human identifier; its `_id` is {@link SYSTEM_ORG_ID}). */
|
|
45
|
+
export declare const SYSTEM_ORG_SLUG = "system";
|
|
24
46
|
/**
|
|
25
|
-
* Check if an orgId or orgName matches the system org.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
47
|
+
* Check if an orgId or orgName/slug matches the system org. Use this instead of
|
|
48
|
+
* comparing directly: the id is now an ObjectId ({@link SYSTEM_ORG_ID}) while the
|
|
49
|
+
* name/slug is 'system' ({@link SYSTEM_ORG_SLUG}), so the two are compared against
|
|
50
|
+
* their respective canonical values.
|
|
29
51
|
*/
|
|
30
52
|
export declare function isSystemOrgId(orgId?: string, orgName?: string): boolean;
|
|
31
53
|
/**
|
|
@@ -88,3 +110,13 @@ export declare function signServiceToken(opts: ServiceTokenOptions): string;
|
|
|
88
110
|
export declare function getServiceAuthHeader(opts: ServiceTokenOptions): string;
|
|
89
111
|
/** True when `req.user.sub` was issued by `signServiceToken` (i.e. starts with `service:`). */
|
|
90
112
|
export declare function isServicePrincipal(req: Request): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* PRE-auth check: cryptographically verify the request carries a valid, signed
|
|
115
|
+
* SERVICE token (`sub` starts with `service:`). Unlike {@link isServicePrincipal}
|
|
116
|
+
* (which reads the already-populated `req.user`), this verifies the bearer token
|
|
117
|
+
* itself, so it is safe to call BEFORE `requireAuth` runs — e.g. the global rate
|
|
118
|
+
* limiter's `skip`, which must not trust the spoofable `x-internal-service`
|
|
119
|
+
* header. Mirrors `requireAuth`'s verification (algorithm pinning + optional
|
|
120
|
+
* issuer/audience) and returns `false` on any missing/invalid/non-service token.
|
|
121
|
+
*/
|
|
122
|
+
export declare function verifyServicePrincipal(req: Request): boolean;
|
package/lib/middleware/auth.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import jwt from 'jsonwebtoken';
|
|
4
4
|
import { HttpStatus } from '../constants/http-status.js';
|
|
5
5
|
import { ErrorCode } from '../types/error-codes.js';
|
|
6
|
+
import { hasPermission } from '../types/permissions.js';
|
|
6
7
|
import { getHeaderString } from '../utils/headers.js';
|
|
7
8
|
import { createLogger } from '../utils/logger.js';
|
|
8
9
|
import { sendError } from '../utils/response.js';
|
|
@@ -108,16 +109,51 @@ export function requireAdmin(req, res, next) {
|
|
|
108
109
|
}
|
|
109
110
|
next();
|
|
110
111
|
}
|
|
111
|
-
/** Organization ID/name that identifies the system (super-admin) tenant. */
|
|
112
|
-
export const SYSTEM_ORG_ID = (process.env.SYSTEM_ORG_ID || 'system').toLowerCase();
|
|
113
112
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
|
|
113
|
+
* Whether the request's user holds `permission`. Superadmins implicitly hold
|
|
114
|
+
* every permission. Reads the resolved `permissions` claim (set at token issue,
|
|
115
|
+
* or re-derived per request by the platform).
|
|
116
|
+
*/
|
|
117
|
+
export function userHasPermission(req, permission) {
|
|
118
|
+
return hasPermission(req.user?.permissions, permission, req.user?.isSuperAdmin);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Requires that the user hold AT LEAST ONE of the given permissions (or be a
|
|
122
|
+
* superadmin). Use after requireAuth. Mirrors `requireRole`'s any-of semantics;
|
|
123
|
+
* pass a single permission for a specific action, or several when any one of
|
|
124
|
+
* them should grant access.
|
|
125
|
+
*/
|
|
126
|
+
export function requirePermission(...permissions) {
|
|
127
|
+
return (req, res, next) => {
|
|
128
|
+
if (!req.user) {
|
|
129
|
+
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
130
|
+
}
|
|
131
|
+
// userHasPermission → hasPermission already grants superadmins every
|
|
132
|
+
// permission, so this single check covers both the superadmin bypass and
|
|
133
|
+
// the any-of membership test without re-inlining either.
|
|
134
|
+
if (permissions.some((p) => userHasPermission(req, p)))
|
|
135
|
+
return next();
|
|
136
|
+
return sendError(res, HttpStatus.FORBIDDEN, `Missing required permission: ${permissions.join(' or ')}`, ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The system tenant's canonical org **id** — a fixed, well-known ObjectId (NOT
|
|
141
|
+
* the string 'system'). This is the single knob every service resolves the
|
|
142
|
+
* system tenant through; override via the `SYSTEM_ORG_ID` env for alternate
|
|
143
|
+
* installs. The system org's human identifier stays the slug/name 'system'
|
|
144
|
+
* (see {@link SYSTEM_ORG_SLUG}); only its `_id` is this ObjectId.
|
|
145
|
+
*/
|
|
146
|
+
export const SYSTEM_ORG_ID = (process.env.SYSTEM_ORG_ID || '000000000000000000000001').toLowerCase();
|
|
147
|
+
/** The system org's well-known slug/name (the human identifier; its `_id` is {@link SYSTEM_ORG_ID}). */
|
|
148
|
+
export const SYSTEM_ORG_SLUG = 'system';
|
|
149
|
+
/**
|
|
150
|
+
* Check if an orgId or orgName/slug matches the system org. Use this instead of
|
|
151
|
+
* comparing directly: the id is now an ObjectId ({@link SYSTEM_ORG_ID}) while the
|
|
152
|
+
* name/slug is 'system' ({@link SYSTEM_ORG_SLUG}), so the two are compared against
|
|
153
|
+
* their respective canonical values.
|
|
118
154
|
*/
|
|
119
155
|
export function isSystemOrgId(orgId, orgName) {
|
|
120
|
-
return orgId?.toLowerCase() === SYSTEM_ORG_ID || orgName?.toLowerCase() ===
|
|
156
|
+
return orgId?.toLowerCase() === SYSTEM_ORG_ID || orgName?.toLowerCase() === SYSTEM_ORG_SLUG;
|
|
121
157
|
}
|
|
122
158
|
/**
|
|
123
159
|
* Check if the request is from a system admin.
|
|
@@ -237,4 +273,30 @@ export function getServiceAuthHeader(opts) {
|
|
|
237
273
|
export function isServicePrincipal(req) {
|
|
238
274
|
return req.user?.sub?.startsWith('service:') ?? false;
|
|
239
275
|
}
|
|
240
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUd0QyxPQUFPLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDL0IsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRXpELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVqRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUUvQyw0REFBNEQ7QUFDNUQsSUFBSSxVQUE4QixDQUFDO0FBQ25DLElBQUkscUJBQXFCLEdBQUcsQ0FBQyxDQUFDO0FBQzlCLE1BQU0sOEJBQThCLEdBQUcsT0FBTyxDQUFDLENBQUMsWUFBWTtBQUU1RCxTQUFTLFlBQVk7SUFDbkIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3ZCLElBQUksQ0FBQyxVQUFVLElBQUksR0FBRyxHQUFHLHFCQUFxQixHQUFHLDhCQUE4QixFQUFFLENBQUM7UUFDaEYsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7UUFDdEMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDO1lBQzNELE1BQU0sSUFBSSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztRQUNqRSxDQUFDO1FBQ0QsSUFBSSxVQUFVLElBQUksVUFBVSxLQUFLLE1BQU0sRUFBRSxDQUFDO1lBQ3hDLE1B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LG9FQUFvRTtJQUNwRSxNQUFNLFdBQVcsR0FBb0I7UUFDbkMsU0FBUyxFQUFFLElBQUksQ0FBQyxVQUFVLElBQUksaUNBQWlDO1FBQy9ELDJFQUEyRTtRQUMzRSx1REFBdUQ7UUFDdkQsU0FBUyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLElBQUksT0FBTyxDQUFrQjtLQUNuRSxDQUFDO0lBQ0YsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVU7UUFBRSxXQUFXLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO0lBQ3hFLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZO1FBQUUsV0FBVyxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQztJQUM5RSxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFlBQVksRUFBRSxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQ3hELENBQUM7QUFFRCxrRkFBa0Y7QUFDbEYsTUFBTSxVQUFVLG9CQUFvQixDQUFDLElBQXlCO0lBQzVELE9BQU8sVUFBVSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0FBQzVDLENBQUM7QUFFRCwrRkFBK0Y7QUFDL0YsTUFBTSxVQUFVLGtCQUFrQixDQUFDLEdBQVk7SUFDN0MsT0FBTyxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksS0FBSyxDQUFDO0FBQ3hELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSwgTmV4dEZ1bmN0aW9uIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgand0IGZyb20gJ2pzb253ZWJ0b2tlbic7XG5pbXBvcnQgeyBIdHRwU3RhdHVzIH0gZnJvbSAnLi4vY29uc3RhbnRzL2h0dHAtc3RhdHVzLmpzJztcbmltcG9ydCB0eXBlIHsgSnd0UGF5bG9hZCB9IGZyb20gJy4uL3R5cGVzL2NvbW1vbi5qcyc7XG5pbXBvcnQgeyBFcnJvckNvZGUgfSBmcm9tICcuLi90eXBlcy9lcnJvci1jb2Rlcy5qcyc7XG5pbXBvcnQgeyBnZXRIZWFkZXJTdHJpbmcgfSBmcm9tICcuLi91dGlscy9oZWFkZXJzLmpzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignYXV0aC1taWRkbGV3YXJlJyk7XG5cbi8qKiBDYWNoZWQgSldUIHNlY3JldCB3aXRoIHBlcmlvZGljIHJlZnJlc2ggZnJvbSBlbnYgdmFyLiAqL1xubGV0IF9qd3RTZWNyZXQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbmxldCBfand0U2VjcmV0UmVmcmVzaGVkQXQgPSAwO1xuY29uc3QgSldUX1NFQ1JFVF9SRUZSRVNIX0lOVEVSVkFMX01TID0gMzAwXzAwMDsgLy8gNSBtaW51dGVzXG5cbmZ1bmN0aW9uIGdldEp3dFNlY3JldCgpOiBzdHJpbmcge1xuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICBpZiAoIV9qd3RTZWNyZXQgfHwgbm93IC0gX2p3dFNlY3JldFJlZnJlc2hlZEF0ID4gSldUX1NFQ1JFVF9SRUZSRVNIX0lOVEVSVkFMX01TKSB7XG4gICAgY29uc3Qgc2VjcmV0ID0gcHJvY2Vzcy5lbnYuSldUX1NFQ1JFVDtcbiAgICBpZiAoIXNlY3JldCkge1xuICAgICAgbG9nZ2VyLmVycm9yKCdKV1RfU0VDUkVUIGVudmlyb25tZW50IHZhcmlhYmxlIGlzIG5vdCBzZXQnKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSldUX1NFQ1JFVCBlbnZpcm9ubWVudCB2YXJpYWJsZSBpcyByZXF1aXJlZCcpO1xuICAgIH1cbiAgICBpZiAoX2p3dFNlY3JldCAmJiBfand0U2VjcmV0ICE9PSBzZWNyZXQpIHtcbiAgICAgIGxvZ2dlci5pbmZvKCdKV1Qgc2VjcmV0IHJvdGF0ZWQnKTtcbiAgICB9XG4gICAgX2p3dFNlY3JldCA9IHNlY3JldDtcbiAgICBfand0U2VjcmV0UmVmcmVzaGVkQXQgPSBub3c7XG4gIH1cbiAgcmV0dXJuIF9qd3RTZWNyZXQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVxdWlyZUF1dGhPcHRpb25zIHtcbiAgLyoqXG4gICAqIEFsbG93IHgtb3JnLWlkL3gtb3JnLW5hbWUgaGVhZGVycyB0byBvdmVycmlkZSB0aGUgSldUJ3Mgb3JnYW5pemF0aW9uIGZpZWxkcy5cbiAgICpcbiAgICogV2hlbiBlbmFibGVkLCB0aGUgYHgtb3JnLWlkYC9geC1vcmctbmFtZWAgaGVhZGVycyBvdmVycmlkZSB0aGUgY2FsbGVyJ3Mgb3JnXG4gICAqIOKAlCBidXQgT05MWSBmb3IgYSB2ZXJpZmllZCBTWVMtQURNSU4gKGBpc1N1cGVyQWRtaW5gIGNsYWltKS4gRm9yIGFueSBvcmRpbmFyeVxuICAgKiBhdXRoZW50aWNhdGVkIHVzZXIgdGhlIGhlYWRlcnMgYXJlIGlnbm9yZWQsIHNvIGVuYWJsaW5nIHRoaXMgY2FuIG5ldmVyIGxldCBhXG4gICAqIG5vcm1hbCB1c2VyIGltcGVyc29uYXRlIGFub3RoZXIgdGVuYW50J3Mgb3JnLiBVc2UgZm9yIGNyb3NzLW9yZyBhZG1pbiB0b29saW5nXG4gICAqIChlLmcuIGEgc3lzYWRtaW4gbWFuYWdpbmcgYSBnaXZlbiBvcmcncyBiaWxsaW5nKS4gSWYgdW5zdXJlLCBsZWF2ZSBpdCBkaXNhYmxlZC5cbiAgICovXG4gIGFsbG93T3JnSGVhZGVyT3ZlcnJpZGU/OiBib29sZWFuO1xufVxuXG4vKiogSldUIGF1dGggbWlkZGxld2FyZS4gVXNlIGRpcmVjdGx5IG9yIGNhbGwgd2l0aCBvcHRpb25zLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBdXRoKFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IHZvaWQ7XG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIG9wdGlvbnM/OiBSZXF1aXJlQXV0aE9wdGlvbnMsXG4pOiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHZvaWQ7XG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIHJlcU9yT3B0aW9ucz86IFJlcXVlc3QgfCBSZXF1aXJlQXV0aE9wdGlvbnMsXG4gIHJlcz86IFJlc3BvbnNlLFxuICBuZXh0PzogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB8ICgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHZvaWQpIHtcbiAgaWYgKHJlcU9yT3B0aW9ucyAmJiByZXMgJiYgbmV4dCAmJiAnaGVhZGVycycgaW4gcmVxT3JPcHRpb25zKSB7XG4gICAgcmV0dXJuIF9yZXF1aXJlQXV0aCh7fSwgcmVxT3JPcHRpb25zIGFzIFJlcXVlc3QsIHJlcywgbmV4dCk7XG4gIH1cblxuICBjb25zdCBvcHRpb25zID0gKHJlcU9yT3B0aW9ucyBhcyBSZXF1aXJlQXV0aE9wdGlvbnMpIHx8IHt9O1xuICByZXR1cm4gKHJlcTogUmVxdWVzdCwgcmVzSW5uZXI6IFJlc3BvbnNlLCBuZXh0SW5uZXI6IE5leHRGdW5jdGlvbikgPT4ge1xuICAgIF9yZXF1aXJlQXV0aChvcHRpb25zLCByZXEsIHJlc0lubmVyLCBuZXh0SW5uZXIpO1xuICB9O1xufVxuXG5mdW5jdGlvbiBfcmVxdWlyZUF1dGgoXG4gIG9wdGlvbnM6IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgY29uc3QgYXV0aEhlYWRlciA9IHJlcS5oZWFkZXJzLmF1dGhvcml6YXRpb247XG5cbiAgaWYgKCFhdXRoSGVhZGVyKSB7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aG9yaXphdGlvbiBoZWFkZXIgcmVxdWlyZWQnLCBFcnJvckNvZGUuVE9LRU5fTUlTU0lORyk7XG4gIH1cblxuICBjb25zdCBwYXJ0cyA9IGF1dGhIZWFkZXIuc3BsaXQoJyAnKTtcbiAgaWYgKHBhcnRzLmxlbmd0aCAhPT0gMiB8fCBwYXJ0c1swXSAhPT0gJ0JlYXJlcicpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdJbnZhbGlkIGF1dGhvcml6YXRpb24gZm9ybWF0LiBVc2U6IEJlYXJlciA8dG9rZW4+JywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBQYXNzIHRocm91Z2ggb3B0aW9uYWwgaXNzdWVyL2F1ZGllbmNlIHZlcmlmaWNhdGlvbiB3aGVuIGVudi1jb25maWd1cmVkLlxuICAgIC8vIFdpdGhvdXQgdGhlc2UsIGEgSldUIHNpZ25lZCBieSBhbnkgc3lzdGVtIHRoYXQgaGFwcGVucyB0byBzaGFyZSB0aGVcbiAgICAvLyBzYW1lIEpXVF9TRUNSRVQgd291bGQgYmUgYWNjZXB0ZWQg4oCUIGRlZmVuY2UtaW4tZGVwdGggZm9yIHNoYXJlZC1zZWNyZXRcbiAgICAvLyBtaXNjb25maWd1cmF0aW9ucyBhY3Jvc3Mgc2VydmljZXMgLyBlbnZpcm9ubWVudHMuXG4gICAgLy8gUGluIHRoZSBhY2NlcHRlZCBhbGdvcml0aG0gdG8gdGhlIGNvbmZpZ3VyZWQgSE1BQyBhbGcgKGRlZmF1bHQgSFMyNTYpLlxuICAgIC8vIFdpdGhvdXQgYW4gYWxsb3ctbGlzdCwgYGp3dC52ZXJpZnlgIGFjY2VwdHMgYW55IGFsZ29yaXRobSB0aGUga2V5IGNhblxuICAgIC8vIHZlcmlmeSDigJQgdGhlIGNsYXNzaWMgYWxnLWNvbmZ1c2lvbiB2ZWN0b3IgKGFuZCBhIGhhcmQgZ3VhcmQgYWdhaW5zdFxuICAgIC8vIGBhbGc6bm9uZWApLiBFbnYtZHJpdmVuIHNvIGl0IHN0YXlzIGluIGxvY2tzdGVwIHdpdGggaG93IHRva2VucyBhcmVcbiAgICAvLyBzaWduZWQgKHNlZSBzaWduU2VydmljZVRva2VuICsgcGxhdGZvcm0ncyBjb25maWcuYXV0aC5qd3QuYWxnb3JpdGhtKS5cbiAgICBjb25zdCB2ZXJpZnlPcHRpb25zOiBqd3QuVmVyaWZ5T3B0aW9ucyA9IHsgYWxnb3JpdGhtczogWyhwcm9jZXNzLmVudi5KV1RfQUxHT1JJVEhNIHx8ICdIUzI1NicpIGFzIGp3dC5BbGdvcml0aG1dIH07XG4gICAgY29uc3QgZXhwZWN0ZWRJc3N1ZXIgPSBwcm9jZXNzLmVudi5KV1RfSVNTVUVSO1xuICAgIGNvbnN0IGV4cGVjdGVkQXVkaWVuY2UgPSBwcm9jZXNzLmVudi5KV1RfQVVESUVOQ0U7XG4gICAgaWYgKGV4cGVjdGVkSXNzdWVyKSB2ZXJpZnlPcHRpb25zLmlzc3VlciA9IGV4cGVjdGVkSXNzdWVyO1xuICAgIGlmIChleHBlY3RlZEF1ZGllbmNlKSB2ZXJpZnlPcHRpb25zLmF1ZGllbmNlID0gZXhwZWN0ZWRBdWRpZW5jZTtcbiAgICBjb25zdCBkZWNvZGVkID0gand0LnZlcmlmeShwYXJ0c1sxXSwgZ2V0Snd0U2VjcmV0KCksIHZlcmlmeU9wdGlvbnMpIGFzIEp3dFBheWxvYWQ7XG5cbiAgICBpZiAoZGVjb2RlZC50eXBlICE9PSAnYWNjZXNzJykge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnT25seSBhY2Nlc3MgdG9rZW5zIGNhbiBiZSB1c2VkIGZvciBBUEkgcmVxdWVzdHMnLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgaWYgKCFkZWNvZGVkLnN1YiB8fCAhZGVjb2RlZC5yb2xlKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdUb2tlbiBtaXNzaW5nIHJlcXVpcmVkIGZpZWxkcycsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICByZXEudXNlciA9IHsgLi4uZGVjb2RlZCB9O1xuXG4gICAgLy8gVGhlIHgtb3JnLWlkL3gtb3JnLW5hbWUgb3ZlcnJpZGUgbGV0cyBhIFNZUy1BRE1JTiBhY3Qgb24gYSBjaG9zZW4gb3JnXG4gICAgLy8gKGNyb3NzLW9yZyBhZG1pbiB0b29saW5nKS4gSXQgaXMgZ2F0ZWQgb24gdGhlIHZlcmlmaWVkIGBpc1N1cGVyQWRtaW5gIGNsYWltXG4gICAgLy8gaGVyZSBzbyB0aGF0IGV2ZW4gYSByb3V0ZSB3aGljaCBtaXN0YWtlbmx5IGVuYWJsZXMgYGFsbG93T3JnSGVhZGVyT3ZlcnJpZGVgXG4gICAgLy8gY2FuIE5FVkVSIGxldCBhbiBvcmRpbmFyeSBhdXRoZW50aWNhdGVkIHVzZXIgc3Bvb2YgYW5vdGhlciB0ZW5hbnQncyBvcmcgdmlhXG4gICAgLy8gdGhlIGhlYWRlciDigJQgZGVmZW5jZS1pbi1kZXB0aCBhZ2FpbnN0IHRoZSBjcm9zcy10ZW5hbnQgYnJlYWsgdGhpcyBjYXVzZWQuXG4gICAgaWYgKG9wdGlvbnMuYWxsb3dPcmdIZWFkZXJPdmVycmlkZSAmJiBkZWNvZGVkLmlzU3VwZXJBZG1pbiA9PT0gdHJ1ZSkge1xuICAgICAgY29uc3QgaGVhZGVyT3JnSWQgPSBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtb3JnLWlkJ10pO1xuICAgICAgY29uc3QgaGVhZGVyT3JnTmFtZSA9IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1vcmctbmFtZSddKTtcbiAgICAgIGlmIChoZWFkZXJPcmdJZCkgcmVxLnVzZXIub3JnYW5pemF0aW9uSWQgPSBoZWFkZXJPcmdJZDtcbiAgICAgIGlmIChoZWFkZXJPcmdOYW1lKSByZXEudXNlci5vcmdhbml6YXRpb25OYW1lID0gaGVhZGVyT3JnTmFtZTtcbiAgICB9XG5cbiAgICBuZXh0KCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2Ygand0LlRva2VuRXhwaXJlZEVycm9yKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdUb2tlbiBoYXMgZXhwaXJlZCcsIEVycm9yQ29kZS5UT0tFTl9FWFBJUkVEKTtcbiAgICB9XG5cbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBqd3QuSnNvbldlYlRva2VuRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgdG9rZW4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gZmFpbGVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXF1aXJlcyBhZG1pbiByb2xlLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguXG4gKiBQZXJtaXRzIHVzZXJzIHdob3NlIHBlci1vcmcgcm9sZSBpcyAnYWRtaW4nIG9yICdvd25lcicuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQWRtaW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghcmVxLnVzZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICB9XG5cbiAgaWYgKHJlcS51c2VyLnJvbGUgIT09ICdhZG1pbicgJiYgcmVxLnVzZXIucm9sZSAhPT0gJ293bmVyJykge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTiwgJ0FkbWluIGFjY2VzcyByZXF1aXJlZCcsIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMpO1xuICB9XG5cbiAgbmV4dCgpO1xufVxuXG4vKiogT3JnYW5pemF0aW9uIElEL25hbWUgdGhhdCBpZGVudGlmaWVzIHRoZSBzeXN0ZW0gKHN1cGVyLWFkbWluKSB0ZW5hbnQuICovXG5leHBvcnQgY29uc3QgU1lTVEVNX09SR19JRCA9IChwcm9jZXNzLmVudi5TWVNURU1fT1JHX0lEIHx8ICdzeXN0ZW0nKS50b0xvd2VyQ2FzZSgpO1xuXG4vKipcbiAqIENoZWNrIGlmIGFuIG9yZ0lkIG9yIG9yZ05hbWUgbWF0Y2hlcyB0aGUgc3lzdGVtIG9yZy5cbiAqIFVzZSB0aGlzIGluc3RlYWQgb2YgY29tcGFyaW5nIGRpcmVjdGx5IGFnYWluc3QgU1lTVEVNX09SR19JRCxcbiAqIGJlY2F1c2UgdGhlIEpXVCBvcmdJZCBpcyBhIGRhdGFiYXNlIElEIChlLmcuIE1vbmdvREIgT2JqZWN0SWQpXG4gKiB3aGlsZSBTWVNURU1fT1JHX0lEIGlzIHRoZSB3ZWxsLWtub3duIG5hbWUgXCJzeXN0ZW1cIi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtT3JnSWQob3JnSWQ/OiBzdHJpbmcsIG9yZ05hbWU/OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIG9yZ0lkPy50b0xvd2VyQ2FzZSgpID09PSBTWVNURU1fT1JHX0lEIHx8IG9yZ05hbWU/LnRvTG93ZXJDYXNlKCkgPT09IFNZU1RFTV9PUkdfSUQ7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgdGhlIHJlcXVlc3QgaXMgZnJvbSBhIHN5c3RlbSBhZG1pbi5cbiAqXG4gKiBBdXRob3JpdHkgaXMgZ3JhbnRlZCBzb2xlbHkgYnkgdGhlIHVzZXItbGV2ZWwgYGlzU3VwZXJBZG1pbmAgZmxhZyBjYXJyaWVkXG4gKiBpbiB0aGUgSldULiBUaGUgXCJtZW1iZXJzaGlwIGluIHRoZSB3ZWxsLWtub3duICdzeXN0ZW0nIG9yZyB3aXRoIHJvbGVcbiAqIGFkbWluL293bmVyXCIgcGF0aCB3YXMgcmVtb3ZlZCDigJQgaXQgY29uZmxhdGVkIGEgUGlwZWxpbmUgQnVpbGRlciBvcGVyYXRvclxuICogd2l0aCBhIHJlYWwgY3VzdG9tZXIgdGVuYW50IGluIHRoZSBkYXRhIG1vZGVsLCBhbmQgbWVhbnQgYW55IHVuaW50ZW5kZWRcbiAqIHdyaXRlIHRoYXQgY3JlYXRlZCBhICdzeXN0ZW0nLW5hbWVkIG9yZyBjb3VsZCBxdWlldGx5IGdyYW50IGNyb3NzLW9yZ1xuICogYXV0aG9yaXR5LiBUaGUgYHN5c3RlbWAgb3JnIHN0aWxsIGV4aXN0cyBhcyBhICpjb250ZW50IGhvbGRlciogZm9yIHNoYXJlZFxuICogc2FtcGxlIGRhdGE7IGl0IGp1c3Qgbm8gbG9uZ2VyIGNvbmZlcnMgcHJpdmlsZWdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTeXN0ZW1BZG1pbihyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5pc1N1cGVyQWRtaW4gPT09IHRydWU7XG59XG5cbi8qKlxuICogV2hldGhlciB0aGUgcmVxdWVzdCdzIHRva2VuIGNhcnJpZXMgYSBzcGVjaWZpYyBjYXBhYmlsaXR5IGBzY29wZWAgKGUuZy5cbiAqIGAncmVwb3J0aW5nOmluZ2VzdCdgKS4gVXNlZCB0byBnYXRlIGVuZHBvaW50cyB0aGF0IGFjY2VwdCBhIG5hcnJvdyBtYWNoaW5lXG4gKiBpZGVudGl0eSDigJQgYSBub3JtYWwgaW50ZXJhY3RpdmUgdXNlciB0b2tlbiBoYXMgbm8gYHNjb3BlYCBhbmQgcmV0dXJucyBmYWxzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc1Njb3BlKHJlcTogUmVxdWVzdCwgc2NvcGU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gcmVxLnVzZXI/LnNjb3BlID09PSBzY29wZTtcbn1cblxuLyoqIFJlcXVpcmVzIHN5c3RlbSBhZG1pbiAoYWRtaW4gcm9sZSArIHN5c3RlbSBvcmdhbml6YXRpb24pLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTeXN0ZW1BZG1pbihcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgaWYgKCFpc1N5c3RlbUFkbWluKHJlcSkpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICdBY2Nlc3MgZGVuaWVkLiBPbmx5IHN5c3RlbSBhZG1pbmlzdHJhdG9ycyBjYW4gcGVyZm9ybSB0aGlzIGFjdGlvbi4nLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9XG4gIG5leHQoKTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlIGEgc3BlY2lmaWMgZmVhdHVyZSBmbGFnLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguXG4gKiBDaGVja3MgdGhlIGBmZWF0dXJlc2AgYXJyYXkgaW4gdGhlIEpXVCBwYXlsb2FkIChzZXQgYXQgdG9rZW4gaXNzdWFuY2UpLlxuICogU3lzYWRtaW5zIChpc1N1cGVyQWRtaW4pIGJ5cGFzcyDigJQgdGhleSBhbHdheXMgaGF2ZSBldmVyeSBmZWF0dXJlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUZlYXR1cmUoZmVhdHVyZTogc3RyaW5nKSB7XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cblxuICAgIC8vIFN5c2FkbWlucyBnZXQgYWxsIGZlYXR1cmVzOyB0aGUgYGZlYXR1cmVzYCBhcnJheSBvbiB0aGVpciB0b2tlbiBpc1xuICAgIC8vIHBvcHVsYXRlZCB3aXRoIGV2ZXJ5IGZsYWcgYXQgaXNzdWFuY2UgdGltZSBidXQgdGhlIGJ5cGFzcyBoZXJlIGtlZXBzXG4gICAgLy8gdGhlIHJ1bGUgZXhwbGljaXQgYW5kIHN1cnZpdmVzIGEgdG9rZW4gaXNzdWVkIGJlZm9yZSBhIG5ldyBmZWF0dXJlXG4gICAgLy8gZmxhZyB3YXMgYWRkZWQuXG4gICAgaWYgKHJlcS51c2VyLmlzU3VwZXJBZG1pbiA9PT0gdHJ1ZSkgcmV0dXJuIG5leHQoKTtcblxuICAgIGlmICghcmVxLnVzZXIuZmVhdHVyZXM/LmluY2x1ZGVzKGZlYXR1cmUpKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICBgVGhpcyBmZWF0dXJlIHJlcXVpcmVzIGEgaGlnaGVyIHBsYW4gKCR7ZmVhdHVyZX0pYCxcbiAgICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9O1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIGVmZmVjdGl2ZSBhY2Nlc3MgbW9kaWZpZXIgZm9yIGFuIGVudGl0eSBiZWluZyBjcmVhdGVkL3VwZGF0ZWQuXG4gKiAncHVibGljJyBpcyBwZXJtaXR0ZWQgZm9yIGFueSBhZG1pbiBvciBvd25lciByb2xlIChzeXN0ZW0gYWRtaW5zIGNyZWF0ZVxuICogY2F0YWxvZy13aWRlIHB1YmxpYyBlbnRpdGllczsgb3JnIGFkbWlucyBjcmVhdGUgb3JnLXdpZGUgcHVibGljIGVudGl0aWVzKS5cbiAqIEV2ZXJ5b25lIGVsc2UgKG1lbWJlciByb2xlLCBubyByb2xlKSBnZXRzICdwcml2YXRlJy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVBY2Nlc3NNb2RpZmllcihyZXE6IFJlcXVlc3QsIHJlcXVlc3RlZDogc3RyaW5nIHwgdW5kZWZpbmVkKTogJ3B1YmxpYycgfCAncHJpdmF0ZScge1xuICBpZiAocmVxdWVzdGVkID09PSAncHVibGljJyAmJiAocmVxLnVzZXI/LnJvbGUgPT09ICdhZG1pbicgfHwgcmVxLnVzZXI/LnJvbGUgPT09ICdvd25lcicpKSB7XG4gICAgcmV0dXJuICdwdWJsaWMnO1xuICB9XG4gIHJldHVybiAncHJpdmF0ZSc7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gU2VydmljZS10by1zZXJ2aWNlIHRva2Vuc1xuLy9cbi8vIEludGVyLXNlcnZpY2UgSFRUUCBjYWxscyAoYmlsbGluZyDihpIgbWVzc2FnZSwgcGxhdGZvcm0g4oaSIGNvbXBsaWFuY2UsIGV0Yy4pXG4vLyBuZWVkIHRvIHNhdGlzZnkgdGhlIHNhbWUgYHJlcXVpcmVBdXRoYCBtaWRkbGV3YXJlIGFzIHVzZXIgcmVxdWVzdHMuXG4vLyBgc2lnblNlcnZpY2VUb2tlbmAgbWludHMgYSBzaG9ydC1saXZlZCBKV1Qgc2lnbmVkIHdpdGggdGhlIHNoYXJlZFxuLy8gSldUX1NFQ1JFVCwgaWRlbnRpZnlpbmcgdGhlIGNhbGxpbmcgc2VydmljZSB2aWEgYHN1YjogJ3NlcnZpY2U6PG5hbWU+J2AuXG4vLyBgcmVxdWlyZUF1dGhgIGFjY2VwdHMgdGhlc2UgdG9rZW5zIHRyYW5zcGFyZW50bHkg4oCUIHRoZXkgcGFzcyBgZGVjb2RlZC5zdWJgXG4vLyBhbmQgYGRlY29kZWQucm9sZWAgY2hlY2tzLCBhbmQgZG93bnN0cmVhbSBgcmVxdWlyZU9yZ2FuaXphdGlvbmAgL1xuLy8gYHJlcXVpcmVBZG1pbmAgcmVseSBvbiB0aGUgb3JnL3JvbGUgZW1iZWRkZWQgaW4gdGhlIHRva2VuLlxuLy9cbi8vIFRva2VucyBkZWZhdWx0IHRvIDUtbWludXRlIFRUTCDigJQgbG9uZyBlbm91Z2ggdG8gc3Vydml2ZSBhIGJhY2tlbmQgaG9wLFxuLy8gc2hvcnQgZW5vdWdoIHRoYXQgYSBsZWFrZWQgdG9rZW4gaXMgbG93LXZhbHVlLlxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmNvbnN0IERFRkFVTFRfU0VSVklDRV9UT0tFTl9UVExfU0VDT05EUyA9IDMwMDtcblxuZXhwb3J0IGludGVyZmFjZSBTZXJ2aWNlVG9rZW5PcHRpb25zIHtcbiAgLyoqIENhbGxpbmcgc2VydmljZSBpZGVudGlmaWVyIChlLmcuICdiaWxsaW5nJywgJ3BsYXRmb3JtJykuIEVtYmVkZGVkIGFzIGBzdWI6IHNlcnZpY2U6PG5hbWU+YC4gKi9cbiAgc2VydmljZU5hbWU6IHN0cmluZztcbiAgLyoqIEFjdGl2ZSBvcmcgY29udGV4dCBmb3IgdGhlIGNhbGwuIFVzZSB0aGUgdGFyZ2V0IHRlbmFudCdzIG9yZyBJRCwgb3IgJ3N5c3RlbScgZm9yIHN5c3RlbS13aWRlIG9wcy4gKi9cbiAgb3JnSWQ/OiBzdHJpbmc7XG4gIC8qKiBBY3RpdmUgb3JnIG5hbWUuIERlZmF1bHRzIHRvIG9yZ0lkLiAqL1xuICBvcmdOYW1lPzogc3RyaW5nO1xuICAvKiogVFRMIGluIHNlY29uZHMgKGRlZmF1bHQgMzAwKS4gKi9cbiAgdHRsU2Vjb25kcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFJvbGUgdGhlIHRva2VuIGNhcnJpZXMgKHJlcXVpcmVkIOKAlCBubyBpbXBsaWNpdCBkZWZhdWx0KS4gKipQYXNzIHRoZSBMT1dFU1RcbiAgICogcm9sZSB0aGUgY2FsbCBhY3R1YWxseSBuZWVkcyoqIChgJ21lbWJlcidgIGZvciByZWFkIC8gZGF0YS1wbGFuZSBjYWxscykgc28gYVxuICAgKiBsZWFrZWQgc2VydmljZSB0b2tlbiBjYW4ndCBwZXJmb3JtIGFkbWluIGFjdGlvbnMgaW4gdGhlIHRhcmdldCBvcmcuXG4gICAqIGBpc0FkbWluYCBpcyBkZXJpdmVkIGZyb20gdGhpcyAoYWRtaW58b3duZXIg4oaSIHRydWUpLlxuICAgKi9cbiAgcm9sZTogJ293bmVyJyB8ICdhZG1pbicgfCAnbWVtYmVyJztcbn1cblxuLyoqXG4gKiBNaW50IGEgSldUIGlkZW50aWZ5aW5nIHRoZSBjYWxsaW5nIHNlcnZpY2UuIFVzZWQgZm9yIGludGVyLXNlcnZpY2UgSFRUUCBjYWxscy5cbiAqIFRoZSB0b2tlbiBzYXRpc2ZpZXMgYHJlcXVpcmVBdXRoYCBhbmQgKHdoZW4gb3JnSWQgaXMgcHJlc2VudCkgYHJlcXVpcmVPcmdhbml6YXRpb25gLlxuICogU2NvcGUgaXQgd2l0aCBgb3B0cy5yb2xlYCDigJQgbGVhc3QgcHJpdmlsZWdlIGtlZXBzIGEgbGVha2VkIHRva2VuIGxvdy12YWx1ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNpZ25TZXJ2aWNlVG9rZW4ob3B0czogU2VydmljZVRva2VuT3B0aW9ucyk6IHN0cmluZyB7XG4gIGNvbnN0IHJvbGUgPSBvcHRzLnJvbGU7XG4gIGNvbnN0IHBheWxvYWQ6IEp3dFBheWxvYWQgPSB7XG4gICAgc3ViOiBgc2VydmljZToke29wdHMuc2VydmljZU5hbWV9YCxcbiAgICB1c2VybmFtZTogYCR7b3B0cy5zZXJ2aWNlTmFtZX0tc2VydmljZWAsXG4gICAgZW1haWw6IGAke29wdHMuc2VydmljZU5hbWV9QGludGVybmFsYCxcbiAgICByb2xlLFxuICAgIGlzQWRtaW46IHJvbGUgPT09ICdvd25lcicgfHwgcm9sZSA9PT0gJ2FkbWluJyxcbiAgICB0eXBlOiAnYWNjZXNzJyxcbiAgICBvcmdhbml6YXRpb25JZDogb3B0cy5vcmdJZCxcbiAgICBvcmdhbml6YXRpb25OYW1lOiBvcHRzLm9yZ05hbWUgPz8gb3B0cy5vcmdJZCxcbiAgfTtcbiAgLy8gTWF0Y2ggdGhlIG9wdGlvbmFsIGlzc3Vlci9hdWRpZW5jZSB0aGF0IHJlcXVpcmVBdXRoIHZlcmlmaWVzLCB3aGVuXG4gIC8vIGNvbmZpZ3VyZWQuIFdpdGhvdXQgdGhlc2UsIGEgc2VydmljZSB0b2tlbiBzaWduZWQgaGVyZSB3b3VsZCBmYWlsXG4gIC8vIHJlcXVpcmVBdXRoIGluIGEgZGVwbG95bWVudCB0aGF0IGhhcyBzZXQgSldUX0lTU1VFUi9KV1RfQVVESUVOQ0UuXG4gIGNvbnN0IHNpZ25PcHRpb25zOiBqd3QuU2lnbk9wdGlvbnMgPSB7XG4gICAgZXhwaXJlc0luOiBvcHRzLnR0bFNlY29uZHMgPz8gREVGQVVMVF9TRVJWSUNFX1RPS0VOX1RUTF9TRUNPTkRTLFxuICAgIC8vIFNpZ24gd2l0aCB0aGUgc2FtZSBjb25maWd1cmVkIGFsZyByZXF1aXJlQXV0aCBwaW5zIG9uIHZlcmlmeSwgc28gc2VydmljZVxuICAgIC8vIHRva2VucyBzdGF5IHZhbGlkIHVuZGVyIGEgbm9uLWRlZmF1bHQgSldUX0FMR09SSVRITS5cbiAgICBhbGdvcml0aG06IChwcm9jZXNzLmVudi5KV1RfQUxHT1JJVEhNIHx8ICdIUzI1NicpIGFzIGp3dC5BbGdvcml0aG0sXG4gIH07XG4gIGlmIChwcm9jZXNzLmVudi5KV1RfSVNTVUVSKSBzaWduT3B0aW9ucy5pc3N1ZXIgPSBwcm9jZXNzLmVudi5KV1RfSVNTVUVSO1xuICBpZiAocHJvY2Vzcy5lbnYuSldUX0FVRElFTkNFKSBzaWduT3B0aW9ucy5hdWRpZW5jZSA9IHByb2Nlc3MuZW52LkpXVF9BVURJRU5DRTtcbiAgcmV0dXJuIGp3dC5zaWduKHBheWxvYWQsIGdldEp3dFNlY3JldCgpLCBzaWduT3B0aW9ucyk7XG59XG5cbi8qKiBDb252ZW5pZW5jZTogcmV0dXJucyBhIGBCZWFyZXIgPHRva2VuPmAgaGVhZGVyIHZhbHVlIGZvciBmZXRjaC9heGlvcyBjYWxscy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXJ2aWNlQXV0aEhlYWRlcihvcHRzOiBTZXJ2aWNlVG9rZW5PcHRpb25zKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBCZWFyZXIgJHtzaWduU2VydmljZVRva2VuKG9wdHMpfWA7XG59XG5cbi8qKiBUcnVlIHdoZW4gYHJlcS51c2VyLnN1YmAgd2FzIGlzc3VlZCBieSBgc2lnblNlcnZpY2VUb2tlbmAgKGkuZS4gc3RhcnRzIHdpdGggYHNlcnZpY2U6YCkuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcTogUmVxdWVzdCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcmVxLnVzZXI/LnN1Yj8uc3RhcnRzV2l0aCgnc2VydmljZTonKSA/PyBmYWxzZTtcbn1cbiJdfQ==
|
|
276
|
+
/**
|
|
277
|
+
* PRE-auth check: cryptographically verify the request carries a valid, signed
|
|
278
|
+
* SERVICE token (`sub` starts with `service:`). Unlike {@link isServicePrincipal}
|
|
279
|
+
* (which reads the already-populated `req.user`), this verifies the bearer token
|
|
280
|
+
* itself, so it is safe to call BEFORE `requireAuth` runs — e.g. the global rate
|
|
281
|
+
* limiter's `skip`, which must not trust the spoofable `x-internal-service`
|
|
282
|
+
* header. Mirrors `requireAuth`'s verification (algorithm pinning + optional
|
|
283
|
+
* issuer/audience) and returns `false` on any missing/invalid/non-service token.
|
|
284
|
+
*/
|
|
285
|
+
export function verifyServicePrincipal(req) {
|
|
286
|
+
const parts = req.headers.authorization?.split(' ');
|
|
287
|
+
if (!parts || parts.length !== 2 || parts[0] !== 'Bearer')
|
|
288
|
+
return false;
|
|
289
|
+
try {
|
|
290
|
+
const verifyOptions = { algorithms: [(process.env.JWT_ALGORITHM || 'HS256')] };
|
|
291
|
+
if (process.env.JWT_ISSUER)
|
|
292
|
+
verifyOptions.issuer = process.env.JWT_ISSUER;
|
|
293
|
+
if (process.env.JWT_AUDIENCE)
|
|
294
|
+
verifyOptions.audience = process.env.JWT_AUDIENCE;
|
|
295
|
+
const decoded = jwt.verify(parts[1], getJwtSecret(), verifyOptions);
|
|
296
|
+
return decoded.type === 'access' && typeof decoded.sub === 'string' && decoded.sub.startsWith('service:');
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUd0QyxPQUFPLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDL0IsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRXpELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNwRCxPQUFPLEVBQW1CLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRWpELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0FBRS9DLDREQUE0RDtBQUM1RCxJQUFJLFVBQThCLENBQUM7QUFDbkMsSUFBSSxxQkFBcUIsR0FBRyxDQUFDLENBQUM7QUFDOUIsTUFBTSw4QkFBOEIsR0FBRyxPQUFPLENBQUMsQ0FBQyxZQUFZO0FBRTVELFNBQVMsWUFBWTtJQUNuQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDdkIsSUFBSSxDQUFDLFVBQVUsSUFBSSxHQUFHLEdBQUcscUJBQXFCLEdBQUcsOEJBQThCLEVBQUUsQ0FBQztRQUNoRixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQztRQUN0QyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixNQUFNLENBQUMsS0FBSyxDQUFDLDRDQUE0QyxDQUFDLENBQUM7WUFDM0QsTUFBTSxJQUFJLEtBQUssQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO1FBQ2pFLENBQUM7UUFDRCxJQUFJ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QyxhQUFhLElBQUksT0FBTyxDQUFrQixDQUFDLEVBQUUsQ0FBQztRQUNuSCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVTtZQUFFLGFBQWEsQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7UUFDMUUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVk7WUFBRSxhQUFhLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDO1FBQ2hGLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksRUFBRSxFQUFFLGFBQWEsQ0FBZSxDQUFDO1FBQ2xGLE9BQU8sT0FBTyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksT0FBTyxPQUFPLENBQUMsR0FBRyxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUM1RyxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlLCBOZXh0RnVuY3Rpb24gfSBmcm9tICdleHByZXNzJztcbmltcG9ydCBqd3QgZnJvbSAnanNvbndlYnRva2VuJztcbmltcG9ydCB7IEh0dHBTdGF0dXMgfSBmcm9tICcuLi9jb25zdGFudHMvaHR0cC1zdGF0dXMuanMnO1xuaW1wb3J0IHR5cGUgeyBKd3RQYXlsb2FkIH0gZnJvbSAnLi4vdHlwZXMvY29tbW9uLmpzJztcbmltcG9ydCB7IEVycm9yQ29kZSB9IGZyb20gJy4uL3R5cGVzL2Vycm9yLWNvZGVzLmpzJztcbmltcG9ydCB7IHR5cGUgUGVybWlzc2lvbiwgaGFzUGVybWlzc2lvbiB9IGZyb20gJy4uL3R5cGVzL3Blcm1pc3Npb25zLmpzJztcbmltcG9ydCB7IGdldEhlYWRlclN0cmluZyB9IGZyb20gJy4uL3V0aWxzL2hlYWRlcnMuanMnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IHNlbmRFcnJvciB9IGZyb20gJy4uL3V0aWxzL3Jlc3BvbnNlLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdhdXRoLW1pZGRsZXdhcmUnKTtcblxuLyoqIENhY2hlZCBKV1Qgc2VjcmV0IHdpdGggcGVyaW9kaWMgcmVmcmVzaCBmcm9tIGVudiB2YXIuICovXG5sZXQgX2p3dFNlY3JldDogc3RyaW5nIHwgdW5kZWZpbmVkO1xubGV0IF9qd3RTZWNyZXRSZWZyZXNoZWRBdCA9IDA7XG5jb25zdCBKV1RfU0VDUkVUX1JFRlJFU0hfSU5URVJWQUxfTVMgPSAzMDBfMDAwOyAvLyA1IG1pbnV0ZXNcblxuZnVuY3Rpb24gZ2V0Snd0U2VjcmV0KCk6IHN0cmluZyB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGlmICghX2p3dFNlY3JldCB8fCBub3cgLSBfand0U2VjcmV0UmVmcmVzaGVkQXQgPiBKV1RfU0VDUkVUX1JFRlJFU0hfSU5URVJWQUxfTVMpIHtcbiAgICBjb25zdCBzZWNyZXQgPSBwcm9jZXNzLmVudi5KV1RfU0VDUkVUO1xuICAgIGlmICghc2VjcmV0KSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0pXVF9TRUNSRVQgZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgbm90IHNldCcpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdKV1RfU0VDUkVUIGVudmlyb25tZW50IHZhcmlhYmxlIGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuICAgIGlmIChfand0U2VjcmV0ICYmIF9qd3RTZWNyZXQgIT09IHNlY3JldCkge1xuICAgICAgbG9nZ2VyLmluZm8oJ0pXVCBzZWNyZXQgcm90YXRlZCcpO1xuICAgIH1cbiAgICBfand0U2VjcmV0ID0gc2VjcmV0O1xuICAgIF9qd3RTZWNyZXRSZWZyZXNoZWRBdCA9IG5vdztcbiAgfVxuICByZXR1cm4gX2p3dFNlY3JldDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXF1aXJlQXV0aE9wdGlvbnMge1xuICAvKipcbiAgICogQWxsb3cgeC1vcmctaWQveC1vcmctbmFtZSBoZWFkZXJzIHRvIG92ZXJyaWRlIHRoZSBKV1QncyBvcmdhbml6YXRpb24gZmllbGRzLlxuICAgKlxuICAgKiBXaGVuIGVuYWJsZWQsIHRoZSBgeC1vcmctaWRgL2B4LW9yZy1uYW1lYCBoZWFkZXJzIG92ZXJyaWRlIHRoZSBjYWxsZXIncyBvcmdcbiAgICog4oCUIGJ1dCBPTkxZIGZvciBhIHZlcmlmaWVkIFNZUy1BRE1JTiAoYGlzU3VwZXJBZG1pbmAgY2xhaW0pLiBGb3IgYW55IG9yZGluYXJ5XG4gICAqIGF1dGhlbnRpY2F0ZWQgdXNlciB0aGUgaGVhZGVycyBhcmUgaWdub3JlZCwgc28gZW5hYmxpbmcgdGhpcyBjYW4gbmV2ZXIgbGV0IGFcbiAgICogbm9ybWFsIHVzZXIgaW1wZXJzb25hdGUgYW5vdGhlciB0ZW5hbnQncyBvcmcuIFVzZSBmb3IgY3Jvc3Mtb3JnIGFkbWluIHRvb2xpbmdcbiAgICogKGUuZy4gYSBzeXNhZG1pbiBtYW5hZ2luZyBhIGdpdmVuIG9yZydzIGJpbGxpbmcpLiBJZiB1bnN1cmUsIGxlYXZlIGl0IGRpc2FibGVkLlxuICAgKi9cbiAgYWxsb3dPcmdIZWFkZXJPdmVycmlkZT86IGJvb2xlYW47XG59XG5cbi8qKiBKV1QgYXV0aCBtaWRkbGV3YXJlLiBVc2UgZGlyZWN0bHkgb3IgY2FsbCB3aXRoIG9wdGlvbnMuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgb3B0aW9ucz86IFJlcXVpcmVBdXRoT3B0aW9ucyxcbik6IChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgcmVxT3JPcHRpb25zPzogUmVxdWVzdCB8IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmVzPzogUmVzcG9uc2UsXG4gIG5leHQ/OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHwgKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZCkge1xuICBpZiAocmVxT3JPcHRpb25zICYmIHJlcyAmJiBuZXh0ICYmICdoZWFkZXJzJyBpbiByZXFPck9wdGlvbnMpIHtcbiAgICByZXR1cm4gX3JlcXVpcmVBdXRoKHt9LCByZXFPck9wdGlvbnMgYXMgUmVxdWVzdCwgcmVzLCBuZXh0KTtcbiAgfVxuXG4gIGNvbnN0IG9wdGlvbnMgPSAocmVxT3JPcHRpb25zIGFzIFJlcXVpcmVBdXRoT3B0aW9ucykgfHwge307XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXNJbm5lcjogUmVzcG9uc2UsIG5leHRJbm5lcjogTmV4dEZ1bmN0aW9uKSA9PiB7XG4gICAgX3JlcXVpcmVBdXRoKG9wdGlvbnMsIHJlcSwgcmVzSW5uZXIsIG5leHRJbm5lcik7XG4gIH07XG59XG5cbmZ1bmN0aW9uIF9yZXF1aXJlQXV0aChcbiAgb3B0aW9uczogUmVxdWlyZUF1dGhPcHRpb25zLFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IHZvaWQge1xuICBjb25zdCBhdXRoSGVhZGVyID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbjtcblxuICBpZiAoIWF1dGhIZWFkZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRob3JpemF0aW9uIGhlYWRlciByZXF1aXJlZCcsIEVycm9yQ29kZS5UT0tFTl9NSVNTSU5HKTtcbiAgfVxuXG4gIGNvbnN0IHBhcnRzID0gYXV0aEhlYWRlci5zcGxpdCgnICcpO1xuICBpZiAocGFydHMubGVuZ3RoICE9PSAyIHx8IHBhcnRzWzBdICE9PSAnQmVhcmVyJykge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgYXV0aG9yaXphdGlvbiBmb3JtYXQuIFVzZTogQmVhcmVyIDx0b2tlbj4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIFBhc3MgdGhyb3VnaCBvcHRpb25hbCBpc3N1ZXIvYXVkaWVuY2UgdmVyaWZpY2F0aW9uIHdoZW4gZW52LWNvbmZpZ3VyZWQuXG4gICAgLy8gV2l0aG91dCB0aGVzZSwgYSBKV1Qgc2lnbmVkIGJ5IGFueSBzeXN0ZW0gdGhhdCBoYXBwZW5zIHRvIHNoYXJlIHRoZVxuICAgIC8vIHNhbWUgSldUX1NFQ1JFVCB3b3VsZCBiZSBhY2NlcHRlZCDigJQgZGVmZW5jZS1pbi1kZXB0aCBmb3Igc2hhcmVkLXNlY3JldFxuICAgIC8vIG1pc2NvbmZpZ3VyYXRpb25zIGFjcm9zcyBzZXJ2aWNlcyAvIGVudmlyb25tZW50cy5cbiAgICAvLyBQaW4gdGhlIGFjY2VwdGVkIGFsZ29yaXRobSB0byB0aGUgY29uZmlndXJlZCBITUFDIGFsZyAoZGVmYXVsdCBIUzI1NikuXG4gICAgLy8gV2l0aG91dCBhbiBhbGxvdy1saXN0LCBgand0LnZlcmlmeWAgYWNjZXB0cyBhbnkgYWxnb3JpdGhtIHRoZSBrZXkgY2FuXG4gICAgLy8gdmVyaWZ5IOKAlCB0aGUgY2xhc3NpYyBhbGctY29uZnVzaW9uIHZlY3RvciAoYW5kIGEgaGFyZCBndWFyZCBhZ2FpbnN0XG4gICAgLy8gYGFsZzpub25lYCkuIEVudi1kcml2ZW4gc28gaXQgc3RheXMgaW4gbG9ja3N0ZXAgd2l0aCBob3cgdG9rZW5zIGFyZVxuICAgIC8vIHNpZ25lZCAoc2VlIHNpZ25TZXJ2aWNlVG9rZW4gKyBwbGF0Zm9ybSdzIGNvbmZpZy5hdXRoLmp3dC5hbGdvcml0aG0pLlxuICAgIGNvbnN0IHZlcmlmeU9wdGlvbnM6IGp3dC5WZXJpZnlPcHRpb25zID0geyBhbGdvcml0aG1zOiBbKHByb2Nlc3MuZW52LkpXVF9BTEdPUklUSE0gfHwgJ0hTMjU2JykgYXMgand0LkFsZ29yaXRobV0gfTtcbiAgICBjb25zdCBleHBlY3RlZElzc3VlciA9IHByb2Nlc3MuZW52LkpXVF9JU1NVRVI7XG4gICAgY29uc3QgZXhwZWN0ZWRBdWRpZW5jZSA9IHByb2Nlc3MuZW52LkpXVF9BVURJRU5DRTtcbiAgICBpZiAoZXhwZWN0ZWRJc3N1ZXIpIHZlcmlmeU9wdGlvbnMuaXNzdWVyID0gZXhwZWN0ZWRJc3N1ZXI7XG4gICAgaWYgKGV4cGVjdGVkQXVkaWVuY2UpIHZlcmlmeU9wdGlvbnMuYXVkaWVuY2UgPSBleHBlY3RlZEF1ZGllbmNlO1xuICAgIGNvbnN0IGRlY29kZWQgPSBqd3QudmVyaWZ5KHBhcnRzWzFdLCBnZXRKd3RTZWNyZXQoKSwgdmVyaWZ5T3B0aW9ucykgYXMgSnd0UGF5bG9hZDtcblxuICAgIGlmIChkZWNvZGVkLnR5cGUgIT09ICdhY2Nlc3MnKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdPbmx5IGFjY2VzcyB0b2tlbnMgY2FuIGJlIHVzZWQgZm9yIEFQSSByZXF1ZXN0cycsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICBpZiAoIWRlY29kZWQuc3ViIHx8ICFkZWNvZGVkLnJvbGUpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Rva2VuIG1pc3NpbmcgcmVxdWlyZWQgZmllbGRzJywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICAgIH1cblxuICAgIHJlcS51c2VyID0geyAuLi5kZWNvZGVkIH07XG5cbiAgICAvLyBUaGUgeC1vcmctaWQveC1vcmctbmFtZSBvdmVycmlkZSBsZXRzIGEgU1lTLUFETUlOIGFjdCBvbiBhIGNob3NlbiBvcmdcbiAgICAvLyAoY3Jvc3Mtb3JnIGFkbWluIHRvb2xpbmcpLiBJdCBpcyBnYXRlZCBvbiB0aGUgdmVyaWZpZWQgYGlzU3VwZXJBZG1pbmAgY2xhaW1cbiAgICAvLyBoZXJlIHNvIHRoYXQgZXZlbiBhIHJvdXRlIHdoaWNoIG1pc3Rha2VubHkgZW5hYmxlcyBgYWxsb3dPcmdIZWFkZXJPdmVycmlkZWBcbiAgICAvLyBjYW4gTkVWRVIgbGV0IGFuIG9yZGluYXJ5IGF1dGhlbnRpY2F0ZWQgdXNlciBzcG9vZiBhbm90aGVyIHRlbmFudCdzIG9yZyB2aWFcbiAgICAvLyB0aGUgaGVhZGVyIOKAlCBkZWZlbmNlLWluLWRlcHRoIGFnYWluc3QgdGhlIGNyb3NzLXRlbmFudCBicmVhayB0aGlzIGNhdXNlZC5cbiAgICBpZiAob3B0aW9ucy5hbGxvd09yZ0hlYWRlck92ZXJyaWRlICYmIGRlY29kZWQuaXNTdXBlckFkbWluID09PSB0cnVlKSB7XG4gICAgICBjb25zdCBoZWFkZXJPcmdJZCA9IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1vcmctaWQnXSk7XG4gICAgICBjb25zdCBoZWFkZXJPcmdOYW1lID0gZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LW9yZy1uYW1lJ10pO1xuICAgICAgaWYgKGhlYWRlck9yZ0lkKSByZXEudXNlci5vcmdhbml6YXRpb25JZCA9IGhlYWRlck9yZ0lkO1xuICAgICAgaWYgKGhlYWRlck9yZ05hbWUpIHJlcS51c2VyLm9yZ2FuaXphdGlvbk5hbWUgPSBoZWFkZXJPcmdOYW1lO1xuICAgIH1cblxuICAgIG5leHQoKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBqd3QuVG9rZW5FeHBpcmVkRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Rva2VuIGhhcyBleHBpcmVkJywgRXJyb3JDb2RlLlRPS0VOX0VYUElSRUQpO1xuICAgIH1cblxuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIGp3dC5Kc29uV2ViVG9rZW5FcnJvcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnSW52YWxpZCB0b2tlbicsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiBmYWlsZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgfVxufVxuXG4vKipcbiAqIFJlcXVpcmVzIGFkbWluIHJvbGUuIFVzZSBhZnRlciByZXF1aXJlQXV0aC5cbiAqIFBlcm1pdHMgdXNlcnMgd2hvc2UgcGVyLW9yZyByb2xlIGlzICdhZG1pbicgb3IgJ293bmVyJy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBZG1pbihcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgaWYgKCFyZXEudXNlcikge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gIH1cblxuICBpZiAocmVxLnVzZXIucm9sZSAhPT0gJ2FkbWluJyAmJiByZXEudXNlci5yb2xlICE9PSAnb3duZXInKSB7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLCAnQWRtaW4gYWNjZXNzIHJlcXVpcmVkJywgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyk7XG4gIH1cblxuICBuZXh0KCk7XG59XG5cbi8qKlxuICogV2hldGhlciB0aGUgcmVxdWVzdCdzIHVzZXIgaG9sZHMgYHBlcm1pc3Npb25gLiBTdXBlcmFkbWlucyBpbXBsaWNpdGx5IGhvbGRcbiAqIGV2ZXJ5IHBlcm1pc3Npb24uIFJlYWRzIHRoZSByZXNvbHZlZCBgcGVybWlzc2lvbnNgIGNsYWltIChzZXQgYXQgdG9rZW4gaXNzdWUsXG4gKiBvciByZS1kZXJpdmVkIHBlciByZXF1ZXN0IGJ5IHRoZSBwbGF0Zm9ybSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VySGFzUGVybWlzc2lvbihyZXE6IFJlcXVlc3QsIHBlcm1pc3Npb246IFBlcm1pc3Npb24pOiBib29sZWFuIHtcbiAgcmV0dXJuIGhhc1Blcm1pc3Npb24ocmVxLnVzZXI/LnBlcm1pc3Npb25zLCBwZXJtaXNzaW9uLCByZXEudXNlcj8uaXNTdXBlckFkbWluKTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlcyB0aGF0IHRoZSB1c2VyIGhvbGQgQVQgTEVBU1QgT05FIG9mIHRoZSBnaXZlbiBwZXJtaXNzaW9ucyAob3IgYmUgYVxuICogc3VwZXJhZG1pbikuIFVzZSBhZnRlciByZXF1aXJlQXV0aC4gTWlycm9ycyBgcmVxdWlyZVJvbGVgJ3MgYW55LW9mIHNlbWFudGljcztcbiAqIHBhc3MgYSBzaW5nbGUgcGVybWlzc2lvbiBmb3IgYSBzcGVjaWZpYyBhY3Rpb24sIG9yIHNldmVyYWwgd2hlbiBhbnkgb25lIG9mXG4gKiB0aGVtIHNob3VsZCBncmFudCBhY2Nlc3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlUGVybWlzc2lvbiguLi5wZXJtaXNzaW9uczogUGVybWlzc2lvbltdKSB7XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cbiAgICAvLyB1c2VySGFzUGVybWlzc2lvbiDihpIgaGFzUGVybWlzc2lvbiBhbHJlYWR5IGdyYW50cyBzdXBlcmFkbWlucyBldmVyeVxuICAgIC8vIHBlcm1pc3Npb24sIHNvIHRoaXMgc2luZ2xlIGNoZWNrIGNvdmVycyBib3RoIHRoZSBzdXBlcmFkbWluIGJ5cGFzcyBhbmRcbiAgICAvLyB0aGUgYW55LW9mIG1lbWJlcnNoaXAgdGVzdCB3aXRob3V0IHJlLWlubGluaW5nIGVpdGhlci5cbiAgICBpZiAocGVybWlzc2lvbnMuc29tZSgocCkgPT4gdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSkpIHJldHVybiBuZXh0KCk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICBgTWlzc2luZyByZXF1aXJlZCBwZXJtaXNzaW9uOiAke3Blcm1pc3Npb25zLmpvaW4oJyBvciAnKX1gLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9O1xufVxuXG4vKipcbiAqIFRoZSBzeXN0ZW0gdGVuYW50J3MgY2Fub25pY2FsIG9yZyAqKmlkKiog4oCUIGEgZml4ZWQsIHdlbGwta25vd24gT2JqZWN0SWQgKE5PVFxuICogdGhlIHN0cmluZyAnc3lzdGVtJykuIFRoaXMgaXMgdGhlIHNpbmdsZSBrbm9iIGV2ZXJ5IHNlcnZpY2UgcmVzb2x2ZXMgdGhlXG4gKiBzeXN0ZW0gdGVuYW50IHRocm91Z2g7IG92ZXJyaWRlIHZpYSB0aGUgYFNZU1RFTV9PUkdfSURgIGVudiBmb3IgYWx0ZXJuYXRlXG4gKiBpbnN0YWxscy4gVGhlIHN5c3RlbSBvcmcncyBodW1hbiBpZGVudGlmaWVyIHN0YXlzIHRoZSBzbHVnL25hbWUgJ3N5c3RlbSdcbiAqIChzZWUge0BsaW5rIFNZU1RFTV9PUkdfU0xVR30pOyBvbmx5IGl0cyBgX2lkYCBpcyB0aGlzIE9iamVjdElkLlxuICovXG5leHBvcnQgY29uc3QgU1lTVEVNX09SR19JRCA9IChwcm9jZXNzLmVudi5TWVNURU1fT1JHX0lEIHx8ICcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEnKS50b0xvd2VyQ2FzZSgpO1xuXG4vKiogVGhlIHN5c3RlbSBvcmcncyB3ZWxsLWtub3duIHNsdWcvbmFtZSAodGhlIGh1bWFuIGlkZW50aWZpZXI7IGl0cyBgX2lkYCBpcyB7QGxpbmsgU1lTVEVNX09SR19JRH0pLiAqL1xuZXhwb3J0IGNvbnN0IFNZU1RFTV9PUkdfU0xVRyA9ICdzeXN0ZW0nO1xuXG4vKipcbiAqIENoZWNrIGlmIGFuIG9yZ0lkIG9yIG9yZ05hbWUvc2x1ZyBtYXRjaGVzIHRoZSBzeXN0ZW0gb3JnLiBVc2UgdGhpcyBpbnN0ZWFkIG9mXG4gKiBjb21wYXJpbmcgZGlyZWN0bHk6IHRoZSBpZCBpcyBub3cgYW4gT2JqZWN0SWQgKHtAbGluayBTWVNURU1fT1JHX0lEfSkgd2hpbGUgdGhlXG4gKiBuYW1lL3NsdWcgaXMgJ3N5c3RlbScgKHtAbGluayBTWVNURU1fT1JHX1NMVUd9KSwgc28gdGhlIHR3byBhcmUgY29tcGFyZWQgYWdhaW5zdFxuICogdGhlaXIgcmVzcGVjdGl2ZSBjYW5vbmljYWwgdmFsdWVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTeXN0ZW1PcmdJZChvcmdJZD86IHN0cmluZywgb3JnTmFtZT86IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gb3JnSWQ/LnRvTG93ZXJDYXNlKCkgPT09IFNZU1RFTV9PUkdfSUQgfHwgb3JnTmFtZT8udG9Mb3dlckNhc2UoKSA9PT0gU1lTVEVNX09SR19TTFVHO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoZSByZXF1ZXN0IGlzIGZyb20gYSBzeXN0ZW0gYWRtaW4uXG4gKlxuICogQXV0aG9yaXR5IGlzIGdyYW50ZWQgc29sZWx5IGJ5IHRoZSB1c2VyLWxldmVsIGBpc1N1cGVyQWRtaW5gIGZsYWcgY2FycmllZFxuICogaW4gdGhlIEpXVC4gVGhlIFwibWVtYmVyc2hpcCBpbiB0aGUgd2VsbC1rbm93biAnc3lzdGVtJyBvcmcgd2l0aCByb2xlXG4gKiBhZG1pbi9vd25lclwiIHBhdGggd2FzIHJlbW92ZWQg4oCUIGl0IGNvbmZsYXRlZCBhIFBpcGVsaW5lIEJ1aWxkZXIgb3BlcmF0b3JcbiAqIHdpdGggYSByZWFsIGN1c3RvbWVyIHRlbmFudCBpbiB0aGUgZGF0YSBtb2RlbCwgYW5kIG1lYW50IGFueSB1bmludGVuZGVkXG4gKiB3cml0ZSB0aGF0IGNyZWF0ZWQgYSAnc3lzdGVtJy1uYW1lZCBvcmcgY291bGQgcXVpZXRseSBncmFudCBjcm9zcy1vcmdcbiAqIGF1dGhvcml0eS4gVGhlIGBzeXN0ZW1gIG9yZyBzdGlsbCBleGlzdHMgYXMgYSAqY29udGVudCBob2xkZXIqIGZvciBzaGFyZWRcbiAqIHNhbXBsZSBkYXRhOyBpdCBqdXN0IG5vIGxvbmdlciBjb25mZXJzIHByaXZpbGVnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtQWRtaW4ocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gIHJldHVybiByZXEudXNlcj8uaXNTdXBlckFkbWluID09PSB0cnVlO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB0b2tlbiBjYXJyaWVzIGEgc3BlY2lmaWMgY2FwYWJpbGl0eSBgc2NvcGVgIChlLmcuXG4gKiBgJ3JlcG9ydGluZzppbmdlc3QnYCkuIFVzZWQgdG8gZ2F0ZSBlbmRwb2ludHMgdGhhdCBhY2NlcHQgYSBuYXJyb3cgbWFjaGluZVxuICogaWRlbnRpdHkg4oCUIGEgbm9ybWFsIGludGVyYWN0aXZlIHVzZXIgdG9rZW4gaGFzIG5vIGBzY29wZWAgYW5kIHJldHVybnMgZmFsc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNTY29wZShyZXE6IFJlcXVlc3QsIHNjb3BlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5zY29wZSA9PT0gc2NvcGU7XG59XG5cbi8qKiBSZXF1aXJlcyBzeXN0ZW0gYWRtaW4gKGFkbWluIHJvbGUgKyBzeXN0ZW0gb3JnYW5pemF0aW9uKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlU3lzdGVtQWRtaW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghaXNTeXN0ZW1BZG1pbihyZXEpKSB7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICAnQWNjZXNzIGRlbmllZC4gT25seSBzeXN0ZW0gYWRtaW5pc3RyYXRvcnMgY2FuIHBlcmZvcm0gdGhpcyBhY3Rpb24uJyxcbiAgICAgIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMsXG4gICAgKTtcbiAgfVxuICBuZXh0KCk7XG59XG5cbi8qKlxuICogUmVxdWlyZSBhIHNwZWNpZmljIGZlYXR1cmUgZmxhZy4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLlxuICogQ2hlY2tzIHRoZSBgZmVhdHVyZXNgIGFycmF5IGluIHRoZSBKV1QgcGF5bG9hZCAoc2V0IGF0IHRva2VuIGlzc3VhbmNlKS5cbiAqIFN5c2FkbWlucyAoaXNTdXBlckFkbWluKSBieXBhc3Mg4oCUIHRoZXkgYWx3YXlzIGhhdmUgZXZlcnkgZmVhdHVyZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVGZWF0dXJlKGZlYXR1cmU6IHN0cmluZykge1xuICByZXR1cm4gKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXEudXNlcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgICB9XG5cbiAgICAvLyBTeXNhZG1pbnMgZ2V0IGFsbCBmZWF0dXJlczsgdGhlIGBmZWF0dXJlc2AgYXJyYXkgb24gdGhlaXIgdG9rZW4gaXNcbiAgICAvLyBwb3B1bGF0ZWQgd2l0aCBldmVyeSBmbGFnIGF0IGlzc3VhbmNlIHRpbWUgYnV0IHRoZSBieXBhc3MgaGVyZSBrZWVwc1xuICAgIC8vIHRoZSBydWxlIGV4cGxpY2l0IGFuZCBzdXJ2aXZlcyBhIHRva2VuIGlzc3VlZCBiZWZvcmUgYSBuZXcgZmVhdHVyZVxuICAgIC8vIGZsYWcgd2FzIGFkZGVkLlxuICAgIGlmIChyZXEudXNlci5pc1N1cGVyQWRtaW4gPT09IHRydWUpIHJldHVybiBuZXh0KCk7XG5cbiAgICBpZiAoIXJlcS51c2VyLmZlYXR1cmVzPy5pbmNsdWRlcyhmZWF0dXJlKSkge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICAgYFRoaXMgZmVhdHVyZSByZXF1aXJlcyBhIGhpZ2hlciBwbGFuICgke2ZlYXR1cmV9KWAsXG4gICAgICAgIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMsXG4gICAgICApO1xuICAgIH1cblxuICAgIG5leHQoKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBlZmZlY3RpdmUgYWNjZXNzIG1vZGlmaWVyIGZvciBhbiBlbnRpdHkgYmVpbmcgY3JlYXRlZC91cGRhdGVkLlxuICogJ3B1YmxpYycgaXMgcGVybWl0dGVkIGZvciBhbnkgYWRtaW4gb3Igb3duZXIgcm9sZSAoc3lzdGVtIGFkbWlucyBjcmVhdGVcbiAqIGNhdGFsb2ctd2lkZSBwdWJsaWMgZW50aXRpZXM7IG9yZyBhZG1pbnMgY3JlYXRlIG9yZy13aWRlIHB1YmxpYyBlbnRpdGllcykuXG4gKiBFdmVyeW9uZSBlbHNlIChtZW1iZXIgcm9sZSwgbm8gcm9sZSkgZ2V0cyAncHJpdmF0ZScuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQWNjZXNzTW9kaWZpZXIocmVxOiBSZXF1ZXN0LCByZXF1ZXN0ZWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6ICdwdWJsaWMnIHwgJ3ByaXZhdGUnIHtcbiAgaWYgKHJlcXVlc3RlZCA9PT0gJ3B1YmxpYycgJiYgKHJlcS51c2VyPy5yb2xlID09PSAnYWRtaW4nIHx8IHJlcS51c2VyPy5yb2xlID09PSAnb3duZXInKSkge1xuICAgIHJldHVybiAncHVibGljJztcbiAgfVxuICByZXR1cm4gJ3ByaXZhdGUnO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFNlcnZpY2UtdG8tc2VydmljZSB0b2tlbnNcbi8vXG4vLyBJbnRlci1zZXJ2aWNlIEhUVFAgY2FsbHMgKGJpbGxpbmcg4oaSIG1lc3NhZ2UsIHBsYXRmb3JtIOKGkiBjb21wbGlhbmNlLCBldGMuKVxuLy8gbmVlZCB0byBzYXRpc2Z5IHRoZSBzYW1lIGByZXF1aXJlQXV0aGAgbWlkZGxld2FyZSBhcyB1c2VyIHJlcXVlc3RzLlxuLy8gYHNpZ25TZXJ2aWNlVG9rZW5gIG1pbnRzIGEgc2hvcnQtbGl2ZWQgSldUIHNpZ25lZCB3aXRoIHRoZSBzaGFyZWRcbi8vIEpXVF9TRUNSRVQsIGlkZW50aWZ5aW5nIHRoZSBjYWxsaW5nIHNlcnZpY2UgdmlhIGBzdWI6ICdzZXJ2aWNlOjxuYW1lPidgLlxuLy8gYHJlcXVpcmVBdXRoYCBhY2NlcHRzIHRoZXNlIHRva2VucyB0cmFuc3BhcmVudGx5IOKAlCB0aGV5IHBhc3MgYGRlY29kZWQuc3ViYFxuLy8gYW5kIGBkZWNvZGVkLnJvbGVgIGNoZWNrcywgYW5kIGRvd25zdHJlYW0gYHJlcXVpcmVPcmdhbml6YXRpb25gIC9cbi8vIGByZXF1aXJlQWRtaW5gIHJlbHkgb24gdGhlIG9yZy9yb2xlIGVtYmVkZGVkIGluIHRoZSB0b2tlbi5cbi8vXG4vLyBUb2tlbnMgZGVmYXVsdCB0byA1LW1pbnV0ZSBUVEwg4oCUIGxvbmcgZW5vdWdoIHRvIHN1cnZpdmUgYSBiYWNrZW5kIGhvcCxcbi8vIHNob3J0IGVub3VnaCB0aGF0IGEgbGVha2VkIHRva2VuIGlzIGxvdy12YWx1ZS5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5jb25zdCBERUZBVUxUX1NFUlZJQ0VfVE9LRU5fVFRMX1NFQ09ORFMgPSAzMDA7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VydmljZVRva2VuT3B0aW9ucyB7XG4gIC8qKiBDYWxsaW5nIHNlcnZpY2UgaWRlbnRpZmllciAoZS5nLiAnYmlsbGluZycsICdwbGF0Zm9ybScpLiBFbWJlZGRlZCBhcyBgc3ViOiBzZXJ2aWNlOjxuYW1lPmAuICovXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmc7XG4gIC8qKiBBY3RpdmUgb3JnIGNvbnRleHQgZm9yIHRoZSBjYWxsLiBVc2UgdGhlIHRhcmdldCB0ZW5hbnQncyBvcmcgSUQsIG9yICdzeXN0ZW0nIGZvciBzeXN0ZW0td2lkZSBvcHMuICovXG4gIG9yZ0lkPzogc3RyaW5nO1xuICAvKiogQWN0aXZlIG9yZyBuYW1lLiBEZWZhdWx0cyB0byBvcmdJZC4gKi9cbiAgb3JnTmFtZT86IHN0cmluZztcbiAgLyoqIFRUTCBpbiBzZWNvbmRzIChkZWZhdWx0IDMwMCkuICovXG4gIHR0bFNlY29uZHM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBSb2xlIHRoZSB0b2tlbiBjYXJyaWVzIChyZXF1aXJlZCDigJQgbm8gaW1wbGljaXQgZGVmYXVsdCkuICoqUGFzcyB0aGUgTE9XRVNUXG4gICAqIHJvbGUgdGhlIGNhbGwgYWN0dWFsbHkgbmVlZHMqKiAoYCdtZW1iZXInYCBmb3IgcmVhZCAvIGRhdGEtcGxhbmUgY2FsbHMpIHNvIGFcbiAgICogbGVha2VkIHNlcnZpY2UgdG9rZW4gY2FuJ3QgcGVyZm9ybSBhZG1pbiBhY3Rpb25zIGluIHRoZSB0YXJnZXQgb3JnLlxuICAgKiBgaXNBZG1pbmAgaXMgZGVyaXZlZCBmcm9tIHRoaXMgKGFkbWlufG93bmVyIOKGkiB0cnVlKS5cbiAgICovXG4gIHJvbGU6ICdvd25lcicgfCAnYWRtaW4nIHwgJ21lbWJlcic7XG59XG5cbi8qKlxuICogTWludCBhIEpXVCBpZGVudGlmeWluZyB0aGUgY2FsbGluZyBzZXJ2aWNlLiBVc2VkIGZvciBpbnRlci1zZXJ2aWNlIEhUVFAgY2FsbHMuXG4gKiBUaGUgdG9rZW4gc2F0aXNmaWVzIGByZXF1aXJlQXV0aGAgYW5kICh3aGVuIG9yZ0lkIGlzIHByZXNlbnQpIGByZXF1aXJlT3JnYW5pemF0aW9uYC5cbiAqIFNjb3BlIGl0IHdpdGggYG9wdHMucm9sZWAg4oCUIGxlYXN0IHByaXZpbGVnZSBrZWVwcyBhIGxlYWtlZCB0b2tlbiBsb3ctdmFsdWUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzaWduU2VydmljZVRva2VuKG9wdHM6IFNlcnZpY2VUb2tlbk9wdGlvbnMpOiBzdHJpbmcge1xuICBjb25zdCByb2xlID0gb3B0cy5yb2xlO1xuICBjb25zdCBwYXlsb2FkOiBKd3RQYXlsb2FkID0ge1xuICAgIHN1YjogYHNlcnZpY2U6JHtvcHRzLnNlcnZpY2VOYW1lfWAsXG4gICAgdXNlcm5hbWU6IGAke29wdHMuc2VydmljZU5hbWV9LXNlcnZpY2VgLFxuICAgIGVtYWlsOiBgJHtvcHRzLnNlcnZpY2VOYW1lfUBpbnRlcm5hbGAsXG4gICAgcm9sZSxcbiAgICBpc0FkbWluOiByb2xlID09PSAnb3duZXInIHx8IHJvbGUgPT09ICdhZG1pbicsXG4gICAgdHlwZTogJ2FjY2VzcycsXG4gICAgb3JnYW5pemF0aW9uSWQ6IG9wdHMub3JnSWQsXG4gICAgb3JnYW5pemF0aW9uTmFtZTogb3B0cy5vcmdOYW1lID8/IG9wdHMub3JnSWQsXG4gIH07XG4gIC8vIE1hdGNoIHRoZSBvcHRpb25hbCBpc3N1ZXIvYXVkaWVuY2UgdGhhdCByZXF1aXJlQXV0aCB2ZXJpZmllcywgd2hlblxuICAvLyBjb25maWd1cmVkLiBXaXRob3V0IHRoZXNlLCBhIHNlcnZpY2UgdG9rZW4gc2lnbmVkIGhlcmUgd291bGQgZmFpbFxuICAvLyByZXF1aXJlQXV0aCBpbiBhIGRlcGxveW1lbnQgdGhhdCBoYXMgc2V0IEpXVF9JU1NVRVIvSldUX0FVRElFTkNFLlxuICBjb25zdCBzaWduT3B0aW9uczogand0LlNpZ25PcHRpb25zID0ge1xuICAgIGV4cGlyZXNJbjogb3B0cy50dGxTZWNvbmRzID8/IERFRkFVTFRfU0VSVklDRV9UT0tFTl9UVExfU0VDT05EUyxcbiAgICAvLyBTaWduIHdpdGggdGhlIHNhbWUgY29uZmlndXJlZCBhbGcgcmVxdWlyZUF1dGggcGlucyBvbiB2ZXJpZnksIHNvIHNlcnZpY2VcbiAgICAvLyB0b2tlbnMgc3RheSB2YWxpZCB1bmRlciBhIG5vbi1kZWZhdWx0IEpXVF9BTEdPUklUSE0uXG4gICAgYWxnb3JpdGhtOiAocHJvY2Vzcy5lbnYuSldUX0FMR09SSVRITSB8fCAnSFMyNTYnKSBhcyBqd3QuQWxnb3JpdGhtLFxuICB9O1xuICBpZiAocHJvY2Vzcy5lbnYuSldUX0lTU1VFUikgc2lnbk9wdGlvbnMuaXNzdWVyID0gcHJvY2Vzcy5lbnYuSldUX0lTU1VFUjtcbiAgaWYgKHByb2Nlc3MuZW52LkpXVF9BVURJRU5DRSkgc2lnbk9wdGlvbnMuYXVkaWVuY2UgPSBwcm9jZXNzLmVudi5KV1RfQVVESUVOQ0U7XG4gIHJldHVybiBqd3Quc2lnbihwYXlsb2FkLCBnZXRKd3RTZWNyZXQoKSwgc2lnbk9wdGlvbnMpO1xufVxuXG4vKiogQ29udmVuaWVuY2U6IHJldHVybnMgYSBgQmVhcmVyIDx0b2tlbj5gIGhlYWRlciB2YWx1ZSBmb3IgZmV0Y2gvYXhpb3MgY2FsbHMuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmljZUF1dGhIZWFkZXIob3B0czogU2VydmljZVRva2VuT3B0aW9ucyk6IHN0cmluZyB7XG4gIHJldHVybiBgQmVhcmVyICR7c2lnblNlcnZpY2VUb2tlbihvcHRzKX1gO1xufVxuXG4vKiogVHJ1ZSB3aGVuIGByZXEudXNlci5zdWJgIHdhcyBpc3N1ZWQgYnkgYHNpZ25TZXJ2aWNlVG9rZW5gIChpLmUuIHN0YXJ0cyB3aXRoIGBzZXJ2aWNlOmApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2VydmljZVByaW5jaXBhbChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5zdWI/LnN0YXJ0c1dpdGgoJ3NlcnZpY2U6JykgPz8gZmFsc2U7XG59XG5cbi8qKlxuICogUFJFLWF1dGggY2hlY2s6IGNyeXB0b2dyYXBoaWNhbGx5IHZlcmlmeSB0aGUgcmVxdWVzdCBjYXJyaWVzIGEgdmFsaWQsIHNpZ25lZFxuICogU0VSVklDRSB0b2tlbiAoYHN1YmAgc3RhcnRzIHdpdGggYHNlcnZpY2U6YCkuIFVubGlrZSB7QGxpbmsgaXNTZXJ2aWNlUHJpbmNpcGFsfVxuICogKHdoaWNoIHJlYWRzIHRoZSBhbHJlYWR5LXBvcHVsYXRlZCBgcmVxLnVzZXJgKSwgdGhpcyB2ZXJpZmllcyB0aGUgYmVhcmVyIHRva2VuXG4gKiBpdHNlbGYsIHNvIGl0IGlzIHNhZmUgdG8gY2FsbCBCRUZPUkUgYHJlcXVpcmVBdXRoYCBydW5zIOKAlCBlLmcuIHRoZSBnbG9iYWwgcmF0ZVxuICogbGltaXRlcidzIGBza2lwYCwgd2hpY2ggbXVzdCBub3QgdHJ1c3QgdGhlIHNwb29mYWJsZSBgeC1pbnRlcm5hbC1zZXJ2aWNlYFxuICogaGVhZGVyLiBNaXJyb3JzIGByZXF1aXJlQXV0aGAncyB2ZXJpZmljYXRpb24gKGFsZ29yaXRobSBwaW5uaW5nICsgb3B0aW9uYWxcbiAqIGlzc3Vlci9hdWRpZW5jZSkgYW5kIHJldHVybnMgYGZhbHNlYCBvbiBhbnkgbWlzc2luZy9pbnZhbGlkL25vbi1zZXJ2aWNlIHRva2VuLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyaWZ5U2VydmljZVByaW5jaXBhbChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgY29uc3QgcGFydHMgPSByZXEuaGVhZGVycy5hdXRob3JpemF0aW9uPy5zcGxpdCgnICcpO1xuICBpZiAoIXBhcnRzIHx8IHBhcnRzLmxlbmd0aCAhPT0gMiB8fCBwYXJ0c1swXSAhPT0gJ0JlYXJlcicpIHJldHVybiBmYWxzZTtcbiAgdHJ5IHtcbiAgICBjb25zdCB2ZXJpZnlPcHRpb25zOiBqd3QuVmVyaWZ5T3B0aW9ucyA9IHsgYWxnb3JpdGhtczogWyhwcm9jZXNzLmVudi5KV1RfQUxHT1JJVEhNIHx8ICdIUzI1NicpIGFzIGp3dC5BbGdvcml0aG1dIH07XG4gICAgaWYgKHByb2Nlc3MuZW52LkpXVF9JU1NVRVIpIHZlcmlmeU9wdGlvbnMuaXNzdWVyID0gcHJvY2Vzcy5lbnYuSldUX0lTU1VFUjtcbiAgICBpZiAocHJvY2Vzcy5lbnYuSldUX0FVRElFTkNFKSB2ZXJpZnlPcHRpb25zLmF1ZGllbmNlID0gcHJvY2Vzcy5lbnYuSldUX0FVRElFTkNFO1xuICAgIGNvbnN0IGRlY29kZWQgPSBqd3QudmVyaWZ5KHBhcnRzWzFdLCBnZXRKd3RTZWNyZXQoKSwgdmVyaWZ5T3B0aW9ucykgYXMgSnd0UGF5bG9hZDtcbiAgICByZXR1cm4gZGVjb2RlZC50eXBlID09PSAnYWNjZXNzJyAmJiB0eXBlb2YgZGVjb2RlZC5zdWIgPT09ICdzdHJpbmcnICYmIGRlY29kZWQuc3ViLnN0YXJ0c1dpdGgoJ3NlcnZpY2U6Jyk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl19
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { NextFunction, Request, Response } from 'express';
|
|
2
|
+
/** Maximum nesting depth accepted by {@link mongoSanitize}. */
|
|
3
|
+
export declare const MAX_SANITIZE_DEPTH = 10;
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when a request payload nests deeper than {@link MAX_SANITIZE_DEPTH}.
|
|
6
|
+
* The middleware maps this to HTTP 400 instead of silently truncating the walk
|
|
7
|
+
* (which would let operator-shaped keys below the cap slip through unsanitized).
|
|
8
|
+
*/
|
|
9
|
+
export declare class PayloadTooDeepError extends Error {
|
|
10
|
+
readonly statusCode: 400;
|
|
11
|
+
constructor(message?: string);
|
|
12
|
+
}
|
|
2
13
|
/**
|
|
3
14
|
* MongoDB operator-injection middleware.
|
|
4
15
|
*
|
|
@@ -18,4 +29,4 @@ import type { NextFunction, Request, Response } from 'express';
|
|
|
18
29
|
* sanitize a snapshot and pin it onto the request instance with
|
|
19
30
|
* `Object.defineProperty`, shadowing the getter for all downstream reads.
|
|
20
31
|
*/
|
|
21
|
-
export declare function mongoSanitize(): (req: Request,
|
|
32
|
+
export declare function mongoSanitize(): (req: Request, res: Response, next: NextFunction) => void;
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
// Copyright 2026 Pipeline Builder Contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { HttpStatus } from '../constants/http-status.js';
|
|
4
|
+
import { ErrorCode } from '../types/error-codes.js';
|
|
5
|
+
import { sendError } from '../utils/response.js';
|
|
6
|
+
/** Maximum nesting depth accepted by {@link mongoSanitize}. */
|
|
7
|
+
export const MAX_SANITIZE_DEPTH = 10;
|
|
8
|
+
/**
|
|
9
|
+
* Thrown when a request payload nests deeper than {@link MAX_SANITIZE_DEPTH}.
|
|
10
|
+
* The middleware maps this to HTTP 400 instead of silently truncating the walk
|
|
11
|
+
* (which would let operator-shaped keys below the cap slip through unsanitized).
|
|
12
|
+
*/
|
|
13
|
+
export class PayloadTooDeepError extends Error {
|
|
14
|
+
statusCode = HttpStatus.BAD_REQUEST;
|
|
15
|
+
constructor(message = `Request payload nesting exceeds the maximum depth of ${MAX_SANITIZE_DEPTH}`) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'PayloadTooDeepError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
3
20
|
/**
|
|
4
21
|
* MongoDB operator-injection middleware.
|
|
5
22
|
*
|
|
@@ -20,22 +37,32 @@
|
|
|
20
37
|
* `Object.defineProperty`, shadowing the getter for all downstream reads.
|
|
21
38
|
*/
|
|
22
39
|
export function mongoSanitize() {
|
|
23
|
-
return (req,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
return (req, res, next) => {
|
|
41
|
+
try {
|
|
42
|
+
if (req.body && typeof req.body === 'object')
|
|
43
|
+
sanitizeObject(req.body);
|
|
44
|
+
if (req.params && typeof req.params === 'object')
|
|
45
|
+
sanitizeObject(req.params);
|
|
46
|
+
if (req.query && typeof req.query === 'object') {
|
|
47
|
+
const q = req.query;
|
|
48
|
+
sanitizeObject(q);
|
|
49
|
+
// Pin the sanitized snapshot so the Express 5 getter can't re-parse a
|
|
50
|
+
// fresh (unsanitized) object on the next access.
|
|
51
|
+
try {
|
|
52
|
+
Object.defineProperty(req, 'query', { value: q, writable: true, configurable: true, enumerable: true });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Express 4 (writable data prop) — the in-place sanitize above sufficed.
|
|
56
|
+
}
|
|
35
57
|
}
|
|
36
|
-
|
|
37
|
-
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
// Reject over-deep payloads with a 400 rather than silently truncating
|
|
61
|
+
// the sanitize walk (which risked leaving deep operator keys in place).
|
|
62
|
+
if (err instanceof PayloadTooDeepError) {
|
|
63
|
+
return sendError(res, err.statusCode, err.message, ErrorCode.VALIDATION_ERROR);
|
|
38
64
|
}
|
|
65
|
+
throw err;
|
|
39
66
|
}
|
|
40
67
|
next();
|
|
41
68
|
};
|
|
@@ -45,9 +72,12 @@ export function mongoSanitize() {
|
|
|
45
72
|
// `constructor.prototype` to inject Mongo operators or pollute Object.prototype.
|
|
46
73
|
const FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
47
74
|
function sanitizeObject(obj, depth = 0) {
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
75
|
+
// Reject pathologically nested input rather than silently returning — a
|
|
76
|
+
// silent cap would leave any operator/dot/prototype keys deeper than the
|
|
77
|
+
// cap un-sanitized. The middleware maps this to a 400.
|
|
78
|
+
if (depth > MAX_SANITIZE_DEPTH) {
|
|
79
|
+
throw new PayloadTooDeepError();
|
|
80
|
+
}
|
|
51
81
|
for (const key of Object.keys(obj)) {
|
|
52
82
|
if (key.startsWith('$') || key.includes('.') || FORBIDDEN_KEYS.has(key)) {
|
|
53
83
|
delete obj[key];
|
|
@@ -67,4 +97,4 @@ function sanitizeObject(obj, depth = 0) {
|
|
|
67
97
|
}
|
|
68
98
|
}
|
|
69
99
|
}
|
|
70
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
100
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9uZ28tc2FuaXRpemUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWlkZGxld2FyZS9tb25nby1zYW5pdGl6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBR3RDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDcEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRWpELCtEQUErRDtBQUMvRCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLENBQUM7QUFFckM7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxtQkFBb0IsU0FBUSxLQUFLO0lBQ25DLFVBQVUsR0FBRyxVQUFVLENBQUMsV0FBVyxDQUFDO0lBQzdDLFlBQVksT0FBTyxHQUFHLHdEQUF3RCxrQkFBa0IsRUFBRTtRQUNoRyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLHFCQUFxQixDQUFDO0lBQ3BDLENBQUM7Q0FDRjtBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLFVBQVUsYUFBYTtJQUMzQixPQUFPLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQixFQUFFLEVBQUU7UUFDekQsSUFBSSxDQUFDO1lBQ0gsSUFBSSxHQUFHLENBQUMsSUFBSSxJQUFJLE9BQU8sR0FBRyxDQUFDLElBQUksS0FBSyxRQUFRO2dCQUFFLGNBQWMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkUsSUFBSSxHQUFHLENBQUMsTUFBTSxJQUFJLE9BQU8sR0FBRyxDQUFDLE1BQU0sS0FBSyxRQUFRO2dCQUFFLGNBQWMsQ0FBQyxHQUFHLENBQUMsTUFBaUMsQ0FBQyxDQUFDO1lBQ3hHLElBQUksR0FBRyxDQUFDLEtBQUssSUFBSSxPQUFPLEdBQUcsQ0FBQyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQy9DLE1BQU0sQ0FBQyxHQUFHLEdBQUcsQ0FBQyxLQUFnQyxDQUFDO2dCQUMvQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ2xCLHNFQUFzRTtnQkFDdEUsaURBQWlEO2dCQUNqRCxJQUFJLENBQUM7b0JBQ0gsTUFBTSxDQUFDLGNBQWMsQ0FBQyxHQUFHLEVBQUUsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQzFHLENBQUM7Z0JBQUMsTUFBTSxDQUFDO29CQUNQLHlFQUF5RTtnQkFDM0UsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLHVFQUF1RTtZQUN2RSx3RUFBd0U7WUFDeEUsSUFBSSxHQUFHLFlBQVksbUJBQW1CLEVBQUUsQ0FBQztnQkFDdkMsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUNqRixDQUFDO1lBQ0QsTUFBTSxHQUFHLENBQUM7UUFDWixDQUFDO1FBQ0QsSUFBSSxFQUFFLENBQUM7SUFDVCxDQUFDLENBQUM7QUFDSixDQUFDO0FBRUQsOEVBQThFO0FBQzlFLDhFQUE4RTtBQUM5RSxpRkFBaUY7QUFDakYsTUFBTSxjQUFjLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsYUFBYSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7QUFFMUUsU0FBUyxjQUFjLENBQUMsR0FBNEIsRUFBRSxLQUFLLEdBQUcsQ0FBQztJQUM3RCx3RUFBd0U7SUFDeEUseUVBQXlFO0lBQ3pFLHVEQUF1RDtJQUN2RCxJQUFJLEtBQUssR0FBRyxrQkFBa0IsRUFBRSxDQUFDO1FBQy9CLE1BQU0sSUFBSSxtQkFBbUIsRUFBRSxDQUFDO0lBQ2xDLENBQUM7SUFDRCxLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNuQyxJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxjQUFjLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDeEUsT0FBTyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDaEIsU0FBUztRQUNYLENBQUM7UUFDRCxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkIsSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0IsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3JCLEtBQUssTUFBTSxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUM7b0JBQ3JCLElBQUksSUFBSSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVE7d0JBQUUsY0FBYyxDQUFDLElBQStCLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUNuRyxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLGNBQWMsQ0FBQyxDQUE0QixFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQztZQUMxRCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB0eXBlIHsgTmV4dEZ1bmN0aW9uLCBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgSHR0cFN0YXR1cyB9IGZyb20gJy4uL2NvbnN0YW50cy9odHRwLXN0YXR1cy5qcyc7XG5pbXBvcnQgeyBFcnJvckNvZGUgfSBmcm9tICcuLi90eXBlcy9lcnJvci1jb2Rlcy5qcyc7XG5pbXBvcnQgeyBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS5qcyc7XG5cbi8qKiBNYXhpbXVtIG5lc3RpbmcgZGVwdGggYWNjZXB0ZWQgYnkge0BsaW5rIG1vbmdvU2FuaXRpemV9LiAqL1xuZXhwb3J0IGNvbnN0IE1BWF9TQU5JVElaRV9ERVBUSCA9IDEwO1xuXG4vKipcbiAqIFRocm93biB3aGVuIGEgcmVxdWVzdCBwYXlsb2FkIG5lc3RzIGRlZXBlciB0aGFuIHtAbGluayBNQVhfU0FOSVRJWkVfREVQVEh9LlxuICogVGhlIG1pZGRsZXdhcmUgbWFwcyB0aGlzIHRvIEhUVFAgNDAwIGluc3RlYWQgb2Ygc2lsZW50bHkgdHJ1bmNhdGluZyB0aGUgd2Fsa1xuICogKHdoaWNoIHdvdWxkIGxldCBvcGVyYXRvci1zaGFwZWQga2V5cyBiZWxvdyB0aGUgY2FwIHNsaXAgdGhyb3VnaCB1bnNhbml0aXplZCkuXG4gKi9cbmV4cG9ydCBjbGFzcyBQYXlsb2FkVG9vRGVlcEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICByZWFkb25seSBzdGF0dXNDb2RlID0gSHR0cFN0YXR1cy5CQURfUkVRVUVTVDtcbiAgY29uc3RydWN0b3IobWVzc2FnZSA9IGBSZXF1ZXN0IHBheWxvYWQgbmVzdGluZyBleGNlZWRzIHRoZSBtYXhpbXVtIGRlcHRoIG9mICR7TUFYX1NBTklUSVpFX0RFUFRIfWApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnUGF5bG9hZFRvb0RlZXBFcnJvcic7XG4gIH1cbn1cblxuLyoqXG4gKiBNb25nb0RCIG9wZXJhdG9yLWluamVjdGlvbiBtaWRkbGV3YXJlLlxuICpcbiAqIFJlY3Vyc2l2ZWx5IHN0cmlwcyBvYmplY3Qga2V5cyBzdGFydGluZyB3aXRoIGAkYCAoTW9uZ28gb3BlcmF0b3JzIGxpa2VcbiAqIGAkbmVgLCBgJGd0YCwgYCR3aGVyZWApIGFuZCBrZXlzIGNvbnRhaW5pbmcgYC5gIChkb3Qtd2Fsa3MpIGZyb21cbiAqIGByZXEuYm9keWAsIGByZXEucXVlcnlgLCBhbmQgYHJlcS5wYXJhbXNgLiBXaXRob3V0IHRoaXMsIGEgSlNPTiByZXF1ZXN0XG4gKiBsaWtlIGB7XCJlbWFpbFwiOiB7XCIkbmVcIjogbnVsbH19YCBhZ2FpbnN0IGEgTW9uZ28tYmFja2VkIHNlcnZpY2UgY2FuIG1hdGNoXG4gKiBhbnkgZG9jdW1lbnQg4oCUIFpvZCBjYXRjaGVzIHRoZSB3cm9uZyAqdHlwZSogYnV0IHdvbid0IHJlYWNoIGludG8gbmVzdGVkXG4gKiBvYmplY3RzIHRvIHN0cmlwIG9wZXJhdG9yLXNoYXBlZCBrZXlzLlxuICpcbiAqIEFwcGx5IEJFRk9SRSBhbnkgTW9uZ28gcXVlcnkgaGFuZGxlciAodHlwaWNhbGx5IHJpZ2h0IGFmdGVyXG4gKiBgZXhwcmVzcy5qc29uKClgKS4gUG9zdGdyZXMtYmFja2VkIHNlcnZpY2VzIGRvbid0IG5lZWQgaXQuXG4gKlxuICogYHJlcS5ib2R5YCBhbmQgYHJlcS5wYXJhbXNgIGFyZSBwbGFpbiB3cml0YWJsZSBvYmplY3RzLCBzbyB0aGV5J3JlIHNhbml0aXplZFxuICogaW4gcGxhY2UuIE9uIEV4cHJlc3MgNSBgcmVxLnF1ZXJ5YCBpcyBhIEdFVFRFUiB0aGF0IHJlLXBhcnNlcyB0aGUgVVJMIGFuZFxuICogcmV0dXJucyBhIGZyZXNoIG9iamVjdCBvbiBldmVyeSBhY2Nlc3Mg4oCUIG11dGF0aW5nIGl0IGlzIGEgbm8tb3Ag4oCUIHNvIHdlXG4gKiBzYW5pdGl6ZSBhIHNuYXBzaG90IGFuZCBwaW4gaXQgb250byB0aGUgcmVxdWVzdCBpbnN0YW5jZSB3aXRoXG4gKiBgT2JqZWN0LmRlZmluZVByb3BlcnR5YCwgc2hhZG93aW5nIHRoZSBnZXR0ZXIgZm9yIGFsbCBkb3duc3RyZWFtIHJlYWRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbW9uZ29TYW5pdGl6ZSgpIHtcbiAgcmV0dXJuIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAocmVxLmJvZHkgJiYgdHlwZW9mIHJlcS5ib2R5ID09PSAnb2JqZWN0Jykgc2FuaXRpemVPYmplY3QocmVxLmJvZHkpO1xuICAgICAgaWYgKHJlcS5wYXJhbXMgJiYgdHlwZW9mIHJlcS5wYXJhbXMgPT09ICdvYmplY3QnKSBzYW5pdGl6ZU9iamVjdChyZXEucGFyYW1zIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KTtcbiAgICAgIGlmIChyZXEucXVlcnkgJiYgdHlwZW9mIHJlcS5xdWVyeSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgY29uc3QgcSA9IHJlcS5xdWVyeSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgICAgc2FuaXRpemVPYmplY3QocSk7XG4gICAgICAgIC8vIFBpbiB0aGUgc2FuaXRpemVkIHNuYXBzaG90IHNvIHRoZSBFeHByZXNzIDUgZ2V0dGVyIGNhbid0IHJlLXBhcnNlIGFcbiAgICAgICAgLy8gZnJlc2ggKHVuc2FuaXRpemVkKSBvYmplY3Qgb24gdGhlIG5leHQgYWNjZXNzLlxuICAgICAgICB0cnkge1xuICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShyZXEsICdxdWVyeScsIHsgdmFsdWU6IHEsIHdyaXRhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUsIGVudW1lcmFibGU6IHRydWUgfSk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIEV4cHJlc3MgNCAod3JpdGFibGUgZGF0YSBwcm9wKSDigJQgdGhlIGluLXBsYWNlIHNhbml0aXplIGFib3ZlIHN1ZmZpY2VkLlxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBSZWplY3Qgb3Zlci1kZWVwIHBheWxvYWRzIHdpdGggYSA0MDAgcmF0aGVyIHRoYW4gc2lsZW50bHkgdHJ1bmNhdGluZ1xuICAgICAgLy8gdGhlIHNhbml0aXplIHdhbGsgKHdoaWNoIHJpc2tlZCBsZWF2aW5nIGRlZXAgb3BlcmF0b3Iga2V5cyBpbiBwbGFjZSkuXG4gICAgICBpZiAoZXJyIGluc3RhbmNlb2YgUGF5bG9hZFRvb0RlZXBFcnJvcikge1xuICAgICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgZXJyLnN0YXR1c0NvZGUsIGVyci5tZXNzYWdlLCBFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUik7XG4gICAgICB9XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICAgIG5leHQoKTtcbiAgfTtcbn1cblxuLy8gUHJvdG90eXBlLXBvbGx1dGlvbiBrZXlzIOKAlCB0aGVzZSBuZXZlciBiZWxvbmcgaW4gSlNPTiByZXF1ZXN0IGJvZGllcywgYW5kIGFcbi8vIGRvd25zdHJlYW0gcmVjdXJzaXZlIG1lcmdlL2Fzc2lnbiBvbiB0aGUgcGFyc2VkIG9iamVjdCBjb3VsZCBvdGhlcndpc2Ugd2Fsa1xuLy8gYGNvbnN0cnVjdG9yLnByb3RvdHlwZWAgdG8gaW5qZWN0IE1vbmdvIG9wZXJhdG9ycyBvciBwb2xsdXRlIE9iamVjdC5wcm90b3R5cGUuXG5jb25zdCBGT1JCSURERU5fS0VZUyA9IG5ldyBTZXQoWydfX3Byb3RvX18nLCAnY29uc3RydWN0b3InLCAncHJvdG90eXBlJ10pO1xuXG5mdW5jdGlvbiBzYW5pdGl6ZU9iamVjdChvYmo6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBkZXB0aCA9IDApOiB2b2lkIHtcbiAgLy8gUmVqZWN0IHBhdGhvbG9naWNhbGx5IG5lc3RlZCBpbnB1dCByYXRoZXIgdGhhbiBzaWxlbnRseSByZXR1cm5pbmcg4oCUIGFcbiAgLy8gc2lsZW50IGNhcCB3b3VsZCBsZWF2ZSBhbnkgb3BlcmF0b3IvZG90L3Byb3RvdHlwZSBrZXlzIGRlZXBlciB0aGFuIHRoZVxuICAvLyBjYXAgdW4tc2FuaXRpemVkLiBUaGUgbWlkZGxld2FyZSBtYXBzIHRoaXMgdG8gYSA0MDAuXG4gIGlmIChkZXB0aCA+IE1BWF9TQU5JVElaRV9ERVBUSCkge1xuICAgIHRocm93IG5ldyBQYXlsb2FkVG9vRGVlcEVycm9yKCk7XG4gIH1cbiAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMob2JqKSkge1xuICAgIGlmIChrZXkuc3RhcnRzV2l0aCgnJCcpIHx8IGtleS5pbmNsdWRlcygnLicpIHx8IEZPUkJJRERFTl9LRVlTLmhhcyhrZXkpKSB7XG4gICAgICBkZWxldGUgb2JqW2tleV07XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgdiA9IG9ialtrZXldO1xuICAgIGlmICh2ICYmIHR5cGVvZiB2ID09PSAnb2JqZWN0Jykge1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodikpIHtcbiAgICAgICAgZm9yIChjb25zdCBpdGVtIG9mIHYpIHtcbiAgICAgICAgICBpZiAoaXRlbSAmJiB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcpIHNhbml0aXplT2JqZWN0KGl0ZW0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGRlcHRoICsgMSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNhbml0aXplT2JqZWN0KHYgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGRlcHRoICsgMSk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=
|