@pipeline-builder/pipeline-manager 4.1.4 → 4.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/agent/env-file.d.ts +1 -1
- package/dist/agent/env-file.js +2 -2
- package/dist/agent/post-steps.d.ts.map +1 -1
- package/dist/agent/post-steps.js +38 -18
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -9
- package/dist/commands/audit-tokens.d.ts.map +1 -1
- package/dist/commands/audit-tokens.js +32 -21
- package/dist/commands/create-pat.d.ts +20 -13
- package/dist/commands/create-pat.d.ts.map +1 -1
- package/dist/commands/create-pat.js +93 -98
- package/dist/commands/login.d.ts +14 -8
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +89 -124
- package/dist/commands/setup-events.d.ts.map +1 -1
- package/dist/commands/setup-events.js +6 -5
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +9 -3
- package/dist/commands/store-token.d.ts +16 -11
- package/dist/commands/store-token.d.ts.map +1 -1
- package/dist/commands/store-token.js +213 -131
- package/dist/lambda/token-renew-handler.d.ts.map +1 -1
- package/dist/lambda/token-renew-handler.js +134 -97
- package/dist/templates/events-stack.json +1 -1
- package/dist/templates/token-renew-stack.json +9 -10
- package/dist/utils/auth-utils.d.ts +21 -38
- package/dist/utils/auth-utils.d.ts.map +1 -1
- package/dist/utils/auth-utils.js +20 -33
- package/dist/utils/command-utils.d.ts +8 -6
- package/dist/utils/command-utils.d.ts.map +1 -1
- package/dist/utils/command-utils.js +71 -15
- package/dist/utils/config-loader.d.ts +2 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +18 -8
- package/dist/utils/credential-store.d.ts +23 -0
- package/dist/utils/credential-store.d.ts.map +1 -0
- package/dist/utils/credential-store.js +92 -0
- package/dist/utils/device-auth.d.ts +59 -0
- package/dist/utils/device-auth.d.ts.map +1 -0
- package/dist/utils/device-auth.js +139 -0
- package/dist/utils/pipeline-config.js +2 -2
- package/dist/utils/platform-secret.d.ts +19 -1
- package/dist/utils/platform-secret.d.ts.map +1 -1
- package/dist/utils/platform-secret.js +26 -4
- package/dist/utils/service-account.d.ts +73 -0
- package/dist/utils/service-account.d.ts.map +1 -0
- package/dist/utils/service-account.js +158 -0
- package/package.json +4 -4
- package/dist/utils/rate-limiter.d.ts +0 -15
- package/dist/utils/rate-limiter.d.ts.map +0 -1
- package/dist/utils/rate-limiter.js +0 -164
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { printInfo, printSuccess, printWarning } from './output-utils.js';
|
|
4
|
+
/** Step-up header the platform reads (see api-core `requireStepUp`). */
|
|
5
|
+
const STEP_UP_HEADER = 'X-Step-Up-Token';
|
|
6
|
+
/** HTTP status of a failed CLI request, or undefined for a transport error.
|
|
7
|
+
* `ApiError` carries it directly; a raw axios error only on the response. */
|
|
8
|
+
function statusOf(err) {
|
|
9
|
+
const e = err;
|
|
10
|
+
const status = e?.status ?? e?.response?.status;
|
|
11
|
+
return typeof status === 'number' ? status : undefined;
|
|
12
|
+
}
|
|
13
|
+
/** The platform's error code on a failed request, when it sent one. */
|
|
14
|
+
function errorCodeOf(err) {
|
|
15
|
+
const data = err?.response?.data;
|
|
16
|
+
return data?.error?.code ?? data?.code;
|
|
17
|
+
}
|
|
18
|
+
/** Unwrap api-core's `{ success, data }` envelope (some paths return data bare). */
|
|
19
|
+
function unwrap(response) {
|
|
20
|
+
const body = response;
|
|
21
|
+
return (body?.data ?? response);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Mint a single-use step-up token for the signed-in operator. Short-lived by
|
|
25
|
+
* design, so callers mint one immediately before each gated write rather than
|
|
26
|
+
* holding one across the whole command.
|
|
27
|
+
*/
|
|
28
|
+
async function stepUp(client, password) {
|
|
29
|
+
try {
|
|
30
|
+
const res = await client.post('/api/auth/step-up', { password });
|
|
31
|
+
const token = unwrap(res)?.stepUpToken;
|
|
32
|
+
if (!token)
|
|
33
|
+
throw new Error('no stepUpToken in response');
|
|
34
|
+
return token;
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
throw new Error('Could not re-verify your password (step-up). Creating a service account and issuing its key '
|
|
38
|
+
+ 'are both step-up gated. Check the password passed via --password / PLATFORM_PASSWORD. '
|
|
39
|
+
+ `(${err instanceof Error ? err.message : String(err)})`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** The org the operator's token is active in. */
|
|
43
|
+
export async function resolveOrganizationId(client) {
|
|
44
|
+
const res = await client.get('/api/organization');
|
|
45
|
+
const orgId = unwrap(res)?.organization?.id;
|
|
46
|
+
if (!orgId) {
|
|
47
|
+
throw new Error('Could not resolve your active organization — the platform returned no organization for this token.');
|
|
48
|
+
}
|
|
49
|
+
return orgId;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The org Role to give a full-privilege machine account: its Super Admin role if
|
|
53
|
+
* the org has one (the system org does), else its Admin role. Both are subject to
|
|
54
|
+
* the ordinary assignment ceiling on the platform side, so this can never grant
|
|
55
|
+
* the account more than the operator holds.
|
|
56
|
+
*/
|
|
57
|
+
async function resolveAdminRoleId(client, orgId) {
|
|
58
|
+
const res = await client.get(`/api/organization/${orgId}/roles`);
|
|
59
|
+
const roles = unwrap(res)?.roles ?? [];
|
|
60
|
+
const role = roles.find((r) => r.grantsRole === 'superadmin') ?? roles.find((r) => r.grantsRole === 'admin');
|
|
61
|
+
if (!role) {
|
|
62
|
+
throw new Error(`Organization ${orgId} has no admin role to grant the machine service account.`);
|
|
63
|
+
}
|
|
64
|
+
return role.id;
|
|
65
|
+
}
|
|
66
|
+
/** Find an existing account by name (the name is the stable machine identifier). */
|
|
67
|
+
async function findAccount(client, orgId, name) {
|
|
68
|
+
const res = await client.get(`/api/organization/${orgId}/service-accounts`);
|
|
69
|
+
const accounts = unwrap(res)?.serviceAccounts ?? [];
|
|
70
|
+
return accounts.find((a) => a.name === name);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Create the account if it isn't there yet, and return its id. IDEMPOTENT: a
|
|
74
|
+
* re-run reuses the existing account (including the 409 race where two runs
|
|
75
|
+
* create it at once), and never re-grants Roles — an operator who narrowed the
|
|
76
|
+
* account's Roles by hand must not have that undone by the next `store-token`.
|
|
77
|
+
*/
|
|
78
|
+
async function ensureAccount(opts, orgId) {
|
|
79
|
+
const existing = await findAccount(opts.client, orgId, opts.accountName);
|
|
80
|
+
if (existing) {
|
|
81
|
+
printInfo('Reusing the existing service account', { account: opts.accountName, id: existing.id });
|
|
82
|
+
return existing.id;
|
|
83
|
+
}
|
|
84
|
+
const roleIds = opts.roles === 'admin' ? [await resolveAdminRoleId(opts.client, orgId)] : [];
|
|
85
|
+
try {
|
|
86
|
+
const res = await opts.client.post(`/api/organization/${orgId}/service-accounts`, { name: opts.accountName, description: opts.description, roleIds }, { [STEP_UP_HEADER]: await stepUp(opts.client, opts.password) });
|
|
87
|
+
const account = unwrap(res)?.serviceAccount;
|
|
88
|
+
if (!account?.id)
|
|
89
|
+
throw new Error('service-account create returned no id');
|
|
90
|
+
printSuccess(`Created the '${opts.accountName}' service account`);
|
|
91
|
+
return account.id;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
if (statusOf(err) === 409) {
|
|
95
|
+
const raced = await findAccount(opts.client, orgId, opts.accountName);
|
|
96
|
+
if (raced)
|
|
97
|
+
return raced.id;
|
|
98
|
+
}
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Revoke one of an account's keys. Best-effort by contract — see the call sites. */
|
|
103
|
+
export async function revokeServiceAccountKey(client, password, orgId, accountId, keyId) {
|
|
104
|
+
await client.delete(`/api/organization/${orgId}/service-accounts/${accountId}/keys/${keyId}`, { [STEP_UP_HEADER]: await stepUp(client, password) });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Issue a key, self-healing past the per-account active-key cap: at the cap the
|
|
108
|
+
* OLDEST active key is retired and the mint retried once. The cap exists to bound
|
|
109
|
+
* a compromise, not to make provisioning fail, and the credential a re-run is
|
|
110
|
+
* replacing is the very thing that should go.
|
|
111
|
+
*/
|
|
112
|
+
async function issueKey(opts, orgId, accountId) {
|
|
113
|
+
const body = {
|
|
114
|
+
name: opts.keyName,
|
|
115
|
+
expiresIn: opts.expiresInSeconds,
|
|
116
|
+
...(opts.scope ? { scope: opts.scope } : {}),
|
|
117
|
+
};
|
|
118
|
+
const mint = async () => unwrap(await opts.client.post(`/api/organization/${orgId}/service-accounts/${accountId}/keys`, body, { [STEP_UP_HEADER]: await stepUp(opts.client, opts.password) }));
|
|
119
|
+
try {
|
|
120
|
+
return await mint();
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
if (statusOf(err) !== 409 && errorCodeOf(err) !== 'SA_KEY_LIMIT')
|
|
124
|
+
throw err;
|
|
125
|
+
const account = await findAccount(opts.client, orgId, opts.accountName);
|
|
126
|
+
const oldest = (account?.keys ?? [])
|
|
127
|
+
.filter((k) => k.status === 'active')
|
|
128
|
+
.sort((a, b) => a.createdAt.localeCompare(b.createdAt))[0];
|
|
129
|
+
if (!oldest)
|
|
130
|
+
throw err;
|
|
131
|
+
printWarning(`Service account '${opts.accountName}' is at its active-key limit — retiring its oldest key (${oldest.id}).`);
|
|
132
|
+
await revokeServiceAccountKey(opts.client, opts.password, orgId, accountId, oldest.id);
|
|
133
|
+
return mint();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Ensure the named service account exists and issue it a fresh key.
|
|
138
|
+
*
|
|
139
|
+
* Deliberately does NOT revoke anything the caller was previously holding: the
|
|
140
|
+
* caller stores the new key first and retires the old one afterwards (see
|
|
141
|
+
* `store-token`), so a failure at any point leaves a working credential in the
|
|
142
|
+
* secret rather than an empty one.
|
|
143
|
+
*/
|
|
144
|
+
export async function provisionServiceAccountKey(opts) {
|
|
145
|
+
const organizationId = await resolveOrganizationId(opts.client);
|
|
146
|
+
const serviceAccountId = await ensureAccount(opts, organizationId);
|
|
147
|
+
const { key, accessKey } = await issueKey(opts, organizationId, serviceAccountId);
|
|
148
|
+
return {
|
|
149
|
+
key,
|
|
150
|
+
keyId: accessKey.id,
|
|
151
|
+
serviceAccountId,
|
|
152
|
+
serviceAccountName: opts.accountName,
|
|
153
|
+
organizationId,
|
|
154
|
+
expiresAt: accessKey.expiresAt,
|
|
155
|
+
scope: accessKey.scope ?? null,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS1hY2NvdW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3NlcnZpY2UtYWNjb3VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBNEJ0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUUxRSx3RUFBd0U7QUFDeEUsTUFBTSxjQUFjLEdBQUcsaUJBQWlCLENBQUM7QUE2Q3pDOzhFQUM4RTtBQUM5RSxTQUFTLFFBQVEsQ0FBQyxHQUFZO0lBQzVCLE1BQU0sQ0FBQyxHQUFHLEdBQTBELENBQUM7SUFDckUsTUFBTSxNQUFNLEdBQUcsQ0FBQyxFQUFFLE1BQU0sSUFBSSxDQUFDLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQztJQUNoRCxPQUFPLE9BQU8sTUFBTSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDekQsQ0FBQztBQUVELHVFQUF1RTtBQUN2RSxTQUFTLFdBQVcsQ0FBQyxHQUFZO0lBQy9CLE1BQU0sSUFBSSxHQUFJLEdBQThFLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQztJQUM3RyxPQUFPLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxJQUFJLElBQUksRUFBRSxJQUFJLENBQUM7QUFDekMsQ0FBQztBQUVELG9GQUFvRjtBQUNwRixTQUFTLE1BQU0sQ0FBSSxRQUFpQjtJQUNsQyxNQUFNLElBQUksR0FBRyxRQUF3QixDQUFDO0lBQ3RDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxJQUFJLFFBQVEsQ0FBTSxDQUFDO0FBQ3ZDLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsS0FBSyxVQUFVLE1BQU0sQ0FBQyxNQUFpQixFQUFFLFFBQWdCO0lBQ3ZELElBQUksQ0FBQztRQUNILE1BQU0sR0FBRyxHQUFHLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBVSxtQkFBbUIsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDMUUsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUEyQixHQUFHLENBQUMsRUFBRSxXQUFXLENBQUM7UUFDakUsSUFBSSxDQUFDLEtBQUs7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7UUFDMUQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE1BQU0sSUFBSSxLQUFLLENBQ2IsOEZBQThGO2NBQzVGLHdGQUF3RjtjQUN4RixJQUFJLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUMxRCxDQUFDO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFRCxpREFBaUQ7QUFDakQsTUFBTSxDQUFDLEtBQUssVUFBVSxxQkFBcUIsQ0FBQyxNQUFpQjtJQUMzRCxNQUFNLEdBQUcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxHQUFHLENBQVUsbUJBQW1CLENBQUMsQ0FBQztJQUMzRCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQXFDLEdBQUcsQ0FBQyxFQUFFLFlBQVksRUFBRSxFQUFFLENBQUM7SUFDaEYsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsTUFBTSxJQUFJLEtBQUssQ0FBQyxvR0FBb0csQ0FBQyxDQUFDO0lBQ3hILENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxNQUFpQixFQUFFLEtBQWE7SUFDaEUsTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLENBQUMsR0FBRyxDQUFVLHFCQUFxQixLQUFLLFFBQVEsQ0FBQyxDQUFDO0lBQzFFLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBeUQsR0FBRyxDQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQztJQUMvRixNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxLQUFLLFlBQVksQ0FBQyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLEtBQUssT0FBTyxDQUFDLENBQUM7SUFDN0csSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQkFBZ0IsS0FBSywwREFBMEQsQ0FBQyxDQUFDO0lBQ25HLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUM7QUFDakIsQ0FBQztBQUVELG9GQUFvRjtBQUNwRixLQUFLLFVBQVUsV0FBVyxDQUFDLE1BQWlCLEVBQUUsS0FBYSxFQUFFLElBQVk7SUFDdkUsTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLENBQUMsR0FBRyxDQUFVLHFCQUFxQixLQUFLLG1CQUFtQixDQUFDLENBQUM7SUFDckYsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUF5QyxHQUFHLENBQUMsRUFBRSxlQUFlLElBQUksRUFBRSxDQUFDO0lBQzVGLE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQztBQUMvQyxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxLQUFLLFVBQVUsYUFBYSxDQUFDLElBQXlCLEVBQUUsS0FBYTtJQUNuRSxNQUFNLFFBQVEsR0FBRyxNQUFNLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDekUsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUNiLFNBQVMsQ0FBQyxzQ0FBc0MsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLEVBQUUsRUFBRSxRQUFRLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNsRyxPQUFPLFFBQVEsQ0FBQyxFQUFFLENBQUM7SUFDckIsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sa0JBQWtCLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDN0YsSUFBSSxDQUFDO1FBQ0gsTUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDaEMscUJBQXFCLEtBQUssbUJBQW1CLEVBQzdDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLEVBQ2xFLEVBQUUsQ0FBQyxjQUFjLENBQUMsRUFBRSxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUMvRCxDQUFDO1FBQ0YsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUF1QyxHQUFHLENBQUMsRUFBRSxjQUFjLENBQUM7UUFDbEYsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyx1Q0FBdUMsQ0FBQyxDQUFDO1FBQzNFLFlBQVksQ0FBQyxnQkFBZ0IsSUFBSSxDQUFDLFdBQVcsbUJBQW1CLENBQUMsQ0FBQztRQUNsRSxPQUFPLE9BQU8sQ0FBQyxFQUFFLENBQUM7SUFDcEIsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixJQUFJLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQztZQUMxQixNQUFNLEtBQUssR0FBRyxNQUFNLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDdEUsSUFBSSxLQUFLO2dCQUFFLE9BQU8sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUM3QixDQUFDO1FBQ0QsTUFBTSxHQUFHLENBQUM7SUFDWixDQUFDO0FBQ0gsQ0FBQztBQUVELHFGQUFxRjtBQUNyRixNQUFNLENBQUMsS0FBSyxVQUFVLHVCQUF1QixDQUMzQyxNQUFpQixFQUNqQixRQUFnQixFQUNoQixLQUFhLEVBQ2IsU0FBaUIsRUFDakIsS0FBYTtJQUViLE1BQU0sTUFBTSxDQUFDLE1BQU0sQ0FDakIscUJBQXFCLEtBQUsscUJBQXFCLFNBQVMsU0FBUyxLQUFLLEVBQUUsRUFDeEUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxFQUFFLE1BQU0sTUFBTSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsRUFBRSxDQUNyRCxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsS0FBSyxVQUFVLFFBQVEsQ0FDckIsSUFBeUIsRUFDekIsS0FBYSxFQUNiLFNBQWlCO0lBRWpCLE1BQU0sSUFBSSxHQUFHO1FBQ1gsSUFBSSxFQUFFLElBQUksQ0FBQyxPQUFPO1FBQ2xCLFNBQVMsRUFBRSxJQUFJLENBQUMsZ0JBQWdCO1FBQ2hDLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUM3QyxDQUFDO0lBQ0YsTUFBTSxJQUFJLEdBQUcsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLENBQzdCLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ3BCLHFCQUFxQixLQUFLLHFCQUFxQixTQUFTLE9BQU8sRUFDL0QsSUFBSSxFQUNKLEVBQUUsQ0FBQyxjQUFjLENBQUMsRUFBRSxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUMvRCxDQUNGLENBQUM7SUFFRixJQUFJLENBQUM7UUFDSCxPQUFPLE1BQU0sSUFBSSxFQUFFLENBQUM7SUFDdEIsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixJQUFJLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLElBQUksV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLGNBQWM7WUFBRSxNQUFNLEdBQUcsQ0FBQztRQUM1RSxNQUFNLE9BQU8sR0FBRyxNQUFNLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDeEUsTUFBTSxNQUFNLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQzthQUNqQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssUUFBUSxDQUFDO2FBQ3BDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdELElBQUksQ0FBQyxNQUFNO1lBQUUsTUFBTSxHQUFHLENBQUM7UUFDdkIsWUFBWSxDQUFDLG9CQUFvQixJQUFJLENBQUMsV0FBVywyREFBMkQsTUFBTSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDM0gsTUFBTSx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdkYsT0FBTyxJQUFJLEVBQUUsQ0FBQztJQUNoQixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLDBCQUEwQixDQUFDLElBQXlCO0lBQ3hFLE1BQU0sY0FBYyxHQUFHLE1BQU0scUJBQXFCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2hFLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxhQUFhLENBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ25FLE1BQU0sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ2xGLE9BQU87UUFDTCxHQUFHO1FBQ0gsS0FBSyxFQUFFLFNBQVMsQ0FBQyxFQUFFO1FBQ25CLGdCQUFnQjtRQUNoQixrQkFBa0IsRUFBRSxJQUFJLENBQUMsV0FBVztRQUNwQyxjQUFjO1FBQ2QsU0FBUyxFQUFFLFNBQVMsQ0FBQyxTQUFTO1FBQzlCLEtBQUssRUFBRSxTQUFTLENBQUMsS0FBSyxJQUFJLElBQUk7S0FDL0IsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBQcm92aXNpb25pbmcgdGhlIG9yZydzIE1BQ0hJTkUgaWRlbnRpdHkgZm9yIHN0b3JlZCBjcmVkZW50aWFscyAoIzEyIC8gI04yKS5cbiAqXG4gKiBFdmVyeSBjcmVkZW50aWFsIHRoZSBDTEkgcGFya3MgaW4gQVdTIFNlY3JldHMgTWFuYWdlciB1c2VkIHRvIGJlIGEgbWFjaGluZVxuICogU0VTU0lPTiBiZWxvbmdpbmcgdG8gd2hvZXZlciByYW4gdGhlIGNvbW1hbmQ6IGEgcGVyc29uJ3MgSldULCByZW5ld2VkIGRhaWx5IGJ5XG4gKiByZS1taW50aW5nIGl0IHVuZGVyIHRoYXQgcGVyc29uJ3Mgc2Vzc2lvbi4gSXQgb3V0bGl2ZWQgdGhlaXIgZW1wbG95bWVudCwgaXRcbiAqIGNhcnJpZWQgdGhlaXIgYXV0aG9yaXR5LCBhbmQgdGhlIGF1ZGl0IHRyYWlsIHJlYWQgYXMgaWYgdGhleSBoYWQgcGVyc29uYWxseVxuICogcHVzaGVkIGV2ZXJ5IGltYWdlLlxuICpcbiAqIFdoYXQgaXQgd3JpdGVzIGluc3RlYWQgaXMgYSBgcGJfc2Ff4oCmYCBrZXkgb24gYW4gb3JnIFNFUlZJQ0UgQUNDT1VOVDpcbiAqICAgLSB0aGUgYWNjb3VudCBpcyB0aGUgcHJpbmNpcGFsLCBzbyBhdWRpdCByb3dzIG5hbWUgaXQsIG5vdCB0aGUgb3BlcmF0b3I7XG4gKiAgIC0gaXRzIFJvbGVzIGFyZSB0aGUgbmFycm93ZXN0IHRoYXQgd29yayDigJQgZm9yIGEgU0NPUEVEIGNyZWRlbnRpYWwgdGhhdCBpcyBub1xuICogICAgIFJvbGVzIGF0IGFsbCwganVzdCB0aGUgb25lIGNhcGFiaWxpdHkgKGByZXBvcnRpbmc6aW5nZXN0YCwgYHJlZ2lzdHJ5OnB1c2hgKTtcbiAqICAgLSB0aGUga2V5IGlzIG9wYXF1ZSBhbmQgc2hvcnQtbGl2ZWQgYXQgdGhlIHBvaW50IG9mIHVzZSAoNS1taW51dGUgZXhjaGFuZ2VkXG4gKiAgICAgdG9rZW5zKSwgc28gcmV2b2tpbmcgaXQgYWN0dWFsbHkgc3RvcHMgdGhlIGF1dG9tYXRpb247XG4gKiAgIC0gaXQgdGFrZXMgbm8gc2VhdCBhbmQgc3Vydml2ZXMgdGhlIG9wZXJhdG9yIGxlYXZpbmcuXG4gKlxuICogQ3JlYXRpbmcgYW4gYWNjb3VudCBhbmQgaXNzdWluZyBhIGtleSBhcmUgQk9USCBzdGVwLXVwIGdhdGVkIG9uIHRoZSBwbGF0Zm9ybSDigJRcbiAqIHRoZXkgbWludCBkdXJhYmxlIGJlYXJlciBjcmVkZW50aWFscywgdGhlIHNhbWUgY2xhc3Mgb2YgYWN0aW9uIGEgcGVyc29uYWwga2V5XG4gKiBpcyBnYXRlZCBmb3IuIFNvIHRoaXMgbW9kdWxlIG5lZWRzIHRoZSBvcGVyYXRvcidzIHBhc3N3b3JkIChgLS1wYXNzd29yZGAgb3JcbiAqIGBQTEFURk9STV9QQVNTV09SRGApLCB3aGljaCBpcyBhbHNvIHRoZSBvbmx5IHJlYXNvbiBgc3RvcmUtdG9rZW5gIHN0aWxsIGhhcyBhXG4gKiBwYXNzd29yZCBwYXRoIGF0IGFsbC4gQSBzdGVwLXVwIHRva2VuIGlzIHNpbmdsZS11c2UgYW5kIGxpdmVzIGFib3V0IGEgbWludXRlLFxuICogc28gb25lIGlzIG1pbnRlZCBpbW1lZGlhdGVseSBiZWZvcmUgZWFjaCBnYXRlZCBjYWxsLlxuICovXG5cbmltcG9ydCB0eXBlIHsgQXBpQ2xpZW50IH0gZnJvbSAnLi9hcGktY2xpZW50LmpzJztcbmltcG9ydCB7IHByaW50SW5mbywgcHJpbnRTdWNjZXNzLCBwcmludFdhcm5pbmcgfSBmcm9tICcuL291dHB1dC11dGlscy5qcyc7XG5cbi8qKiBTdGVwLXVwIGhlYWRlciB0aGUgcGxhdGZvcm0gcmVhZHMgKHNlZSBhcGktY29yZSBgcmVxdWlyZVN0ZXBVcGApLiAqL1xuY29uc3QgU1RFUF9VUF9IRUFERVIgPSAnWC1TdGVwLVVwLVRva2VuJztcblxuLyoqIFdoYXQgdGhlIGNhbGxlciB3YW50cyBwcm92aXNpb25lZC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUHJvdmlzaW9uS2V5T3B0aW9ucyB7XG4gIC8qKiBBbiBhdXRoZW50aWNhdGVkIGNsaWVudCBmb3IgdGhlIG9wZXJhdG9yJ3Mgb3duIHNlc3Npb24uICovXG4gIGNsaWVudDogQXBpQ2xpZW50O1xuICAvKiogVGhlIG9wZXJhdG9yJ3MgcGFzc3dvcmQg4oCUIHJlcXVpcmVkLCBiZWNhdXNlIGV2ZXJ5IGtleSB3cml0ZSBpcyBzdGVwLXVwIGdhdGVkLiAqL1xuICBwYXNzd29yZDogc3RyaW5nO1xuICAvKiogTWFjaGluZSBuYW1lIG9mIHRoZSBzZXJ2aWNlIGFjY291bnQgKGBbYS16MC05XVthLXowLTlfLV17MSw2M31gKS4gKi9cbiAgYWNjb3VudE5hbWU6IHN0cmluZztcbiAgLyoqIEh1bWFuIGRlc2NyaXB0aW9uIHJlY29yZGVkIG9uIGEgbmV3bHkgY3JlYXRlZCBhY2NvdW50LiAqL1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAvKipcbiAgICogUm9sZXMgdG8gZ3JhbnQgYSBORVdMWSBjcmVhdGVkIGFjY291bnQ6IGAnYWRtaW4nYCBmb3IgdGhlIGZ1bGwtcHJpdmlsZWdlXG4gICAqIHBsYXRmb3JtIGNyZWRlbnRpYWwgKHN5bnRoL2RlcGxveSBjYWxsYmFja3MsIHBsdWdpbiBsb29rdXAsIGltYWdlIHB1c2gpLFxuICAgKiBgJ25vbmUnYCBmb3IgYSBzY29wZWQgY3JlZGVudGlhbCwgd2hpY2ggbmVlZHMgbm8gUm9sZXMgYXQgYWxsLlxuICAgKi9cbiAgcm9sZXM6ICdhZG1pbicgfCAnbm9uZSc7XG4gIC8qKiBOYXJyb3cgY2FwYWJpbGl0eSBzY29wZSBzdGFtcGVkIG9uIHRoZSBLRVkgKG5vdCB0aGUgYWNjb3VudCkuICovXG4gIHNjb3BlPzogc3RyaW5nO1xuICAvKiogS2V5IGxpZmV0aW1lIGluIHNlY29uZHMgKHBsYXRmb3JtIGNhcHMgdGhpcyBhdCAzNjUgZGF5cykuICovXG4gIGV4cGlyZXNJblNlY29uZHM6IG51bWJlcjtcbiAgLyoqIEtleSBsYWJlbCDigJQgc2hvd24gb24gdGhlIG9yZydzIHNlcnZpY2UtYWNjb3VudHMgcGFnZS4gKi9cbiAga2V5TmFtZTogc3RyaW5nO1xufVxuXG4vKiogQSBmcmVzaGx5IG1pbnRlZCBrZXksIHBsdXMgZXZlcnl0aGluZyB0aGUgc2VjcmV0IG5lZWRzIHRvIHJlY29yZCBhYm91dCBpdC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUHJvdmlzaW9uZWRLZXkge1xuICAvKiogVGhlIHJhdyBgcGJfc2Ff4oCmYCBrZXkg4oCUIHJldHVybmVkIE9OQ0UgYnkgdGhlIHBsYXRmb3JtLCBuZXZlciByZWFkYWJsZSBhZ2Fpbi4gKi9cbiAga2V5OiBzdHJpbmc7XG4gIGtleUlkOiBzdHJpbmc7XG4gIHNlcnZpY2VBY2NvdW50SWQ6IHN0cmluZztcbiAgc2VydmljZUFjY291bnROYW1lOiBzdHJpbmc7XG4gIG9yZ2FuaXphdGlvbklkOiBzdHJpbmc7XG4gIGV4cGlyZXNBdDogc3RyaW5nO1xuICBzY29wZTogc3RyaW5nIHwgbnVsbDtcbn1cblxuLyoqIE5hcnJvdyBzaGFwZSBvZiBhIHNlcnZpY2UtYWNjb3VudCBsaXN0aW5nIGVudHJ5LiAqL1xuaW50ZXJmYWNlIEFjY291bnRTdW1tYXJ5IHtcbiAgaWQ6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBrZXlzPzogQXJyYXk8eyBpZDogc3RyaW5nOyBzdGF0dXM6IHN0cmluZzsgY3JlYXRlZEF0OiBzdHJpbmcgfT47XG59XG5cbi8qKiBIVFRQIHN0YXR1cyBvZiBhIGZhaWxlZCBDTEkgcmVxdWVzdCwgb3IgdW5kZWZpbmVkIGZvciBhIHRyYW5zcG9ydCBlcnJvci5cbiAqICBgQXBpRXJyb3JgIGNhcnJpZXMgaXQgZGlyZWN0bHk7IGEgcmF3IGF4aW9zIGVycm9yIG9ubHkgb24gdGhlIHJlc3BvbnNlLiAqL1xuZnVuY3Rpb24gc3RhdHVzT2YoZXJyOiB1bmtub3duKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZSA9IGVyciBhcyB7IHN0YXR1cz86IG51bWJlcjsgcmVzcG9uc2U/OiB7IHN0YXR1cz86IG51bWJlciB9IH07XG4gIGNvbnN0IHN0YXR1cyA9IGU/LnN0YXR1cyA/PyBlPy5yZXNwb25zZT8uc3RhdHVzO1xuICByZXR1cm4gdHlwZW9mIHN0YXR1cyA9PT0gJ251bWJlcicgPyBzdGF0dXMgOiB1bmRlZmluZWQ7XG59XG5cbi8qKiBUaGUgcGxhdGZvcm0ncyBlcnJvciBjb2RlIG9uIGEgZmFpbGVkIHJlcXVlc3QsIHdoZW4gaXQgc2VudCBvbmUuICovXG5mdW5jdGlvbiBlcnJvckNvZGVPZihlcnI6IHVua25vd24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBkYXRhID0gKGVyciBhcyB7IHJlc3BvbnNlPzogeyBkYXRhPzogeyBlcnJvcj86IHsgY29kZT86IHN0cmluZyB9OyBjb2RlPzogc3RyaW5nIH0gfSB9KT8ucmVzcG9uc2U/LmRhdGE7XG4gIHJldHVybiBkYXRhPy5lcnJvcj8uY29kZSA/PyBkYXRhPy5jb2RlO1xufVxuXG4vKiogVW53cmFwIGFwaS1jb3JlJ3MgYHsgc3VjY2VzcywgZGF0YSB9YCBlbnZlbG9wZSAoc29tZSBwYXRocyByZXR1cm4gZGF0YSBiYXJlKS4gKi9cbmZ1bmN0aW9uIHVud3JhcDxUPihyZXNwb25zZTogdW5rbm93bik6IFQge1xuICBjb25zdCBib2R5ID0gcmVzcG9uc2UgYXMgeyBkYXRhPzogVCB9O1xuICByZXR1cm4gKGJvZHk/LmRhdGEgPz8gcmVzcG9uc2UpIGFzIFQ7XG59XG5cbi8qKlxuICogTWludCBhIHNpbmdsZS11c2Ugc3RlcC11cCB0b2tlbiBmb3IgdGhlIHNpZ25lZC1pbiBvcGVyYXRvci4gU2hvcnQtbGl2ZWQgYnlcbiAqIGRlc2lnbiwgc28gY2FsbGVycyBtaW50IG9uZSBpbW1lZGlhdGVseSBiZWZvcmUgZWFjaCBnYXRlZCB3cml0ZSByYXRoZXIgdGhhblxuICogaG9sZGluZyBvbmUgYWNyb3NzIHRoZSB3aG9sZSBjb21tYW5kLlxuICovXG5hc3luYyBmdW5jdGlvbiBzdGVwVXAoY2xpZW50OiBBcGlDbGllbnQsIHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGNsaWVudC5wb3N0PHVua25vd24+KCcvYXBpL2F1dGgvc3RlcC11cCcsIHsgcGFzc3dvcmQgfSk7XG4gICAgY29uc3QgdG9rZW4gPSB1bndyYXA8eyBzdGVwVXBUb2tlbj86IHN0cmluZyB9PihyZXMpPy5zdGVwVXBUb2tlbjtcbiAgICBpZiAoIXRva2VuKSB0aHJvdyBuZXcgRXJyb3IoJ25vIHN0ZXBVcFRva2VuIGluIHJlc3BvbnNlJyk7XG4gICAgcmV0dXJuIHRva2VuO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnQ291bGQgbm90IHJlLXZlcmlmeSB5b3VyIHBhc3N3b3JkIChzdGVwLXVwKS4gQ3JlYXRpbmcgYSBzZXJ2aWNlIGFjY291bnQgYW5kIGlzc3VpbmcgaXRzIGtleSAnXG4gICAgICArICdhcmUgYm90aCBzdGVwLXVwIGdhdGVkLiBDaGVjayB0aGUgcGFzc3dvcmQgcGFzc2VkIHZpYSAtLXBhc3N3b3JkIC8gUExBVEZPUk1fUEFTU1dPUkQuICdcbiAgICAgICsgYCgke2VyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKX0pYCxcbiAgICApO1xuICB9XG59XG5cbi8qKiBUaGUgb3JnIHRoZSBvcGVyYXRvcidzIHRva2VuIGlzIGFjdGl2ZSBpbi4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXNvbHZlT3JnYW5pemF0aW9uSWQoY2xpZW50OiBBcGlDbGllbnQpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCByZXMgPSBhd2FpdCBjbGllbnQuZ2V0PHVua25vd24+KCcvYXBpL29yZ2FuaXphdGlvbicpO1xuICBjb25zdCBvcmdJZCA9IHVud3JhcDx7IG9yZ2FuaXphdGlvbj86IHsgaWQ/OiBzdHJpbmcgfSB9PihyZXMpPy5vcmdhbml6YXRpb24/LmlkO1xuICBpZiAoIW9yZ0lkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgcmVzb2x2ZSB5b3VyIGFjdGl2ZSBvcmdhbml6YXRpb24g4oCUIHRoZSBwbGF0Zm9ybSByZXR1cm5lZCBubyBvcmdhbml6YXRpb24gZm9yIHRoaXMgdG9rZW4uJyk7XG4gIH1cbiAgcmV0dXJuIG9yZ0lkO1xufVxuXG4vKipcbiAqIFRoZSBvcmcgUm9sZSB0byBnaXZlIGEgZnVsbC1wcml2aWxlZ2UgbWFjaGluZSBhY2NvdW50OiBpdHMgU3VwZXIgQWRtaW4gcm9sZSBpZlxuICogdGhlIG9yZyBoYXMgb25lICh0aGUgc3lzdGVtIG9yZyBkb2VzKSwgZWxzZSBpdHMgQWRtaW4gcm9sZS4gQm90aCBhcmUgc3ViamVjdCB0b1xuICogdGhlIG9yZGluYXJ5IGFzc2lnbm1lbnQgY2VpbGluZyBvbiB0aGUgcGxhdGZvcm0gc2lkZSwgc28gdGhpcyBjYW4gbmV2ZXIgZ3JhbnRcbiAqIHRoZSBhY2NvdW50IG1vcmUgdGhhbiB0aGUgb3BlcmF0b3IgaG9sZHMuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVBZG1pblJvbGVJZChjbGllbnQ6IEFwaUNsaWVudCwgb3JnSWQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHJlcyA9IGF3YWl0IGNsaWVudC5nZXQ8dW5rbm93bj4oYC9hcGkvb3JnYW5pemF0aW9uLyR7b3JnSWR9L3JvbGVzYCk7XG4gIGNvbnN0IHJvbGVzID0gdW53cmFwPHsgcm9sZXM/OiBBcnJheTx7IGlkOiBzdHJpbmc7IGdyYW50c1JvbGU/OiBzdHJpbmcgfT4gfT4ocmVzKT8ucm9sZXMgPz8gW107XG4gIGNvbnN0IHJvbGUgPSByb2xlcy5maW5kKChyKSA9PiByLmdyYW50c1JvbGUgPT09ICdzdXBlcmFkbWluJykgPz8gcm9sZXMuZmluZCgocikgPT4gci5ncmFudHNSb2xlID09PSAnYWRtaW4nKTtcbiAgaWYgKCFyb2xlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBPcmdhbml6YXRpb24gJHtvcmdJZH0gaGFzIG5vIGFkbWluIHJvbGUgdG8gZ3JhbnQgdGhlIG1hY2hpbmUgc2VydmljZSBhY2NvdW50LmApO1xuICB9XG4gIHJldHVybiByb2xlLmlkO1xufVxuXG4vKiogRmluZCBhbiBleGlzdGluZyBhY2NvdW50IGJ5IG5hbWUgKHRoZSBuYW1lIGlzIHRoZSBzdGFibGUgbWFjaGluZSBpZGVudGlmaWVyKS4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZpbmRBY2NvdW50KGNsaWVudDogQXBpQ2xpZW50LCBvcmdJZDogc3RyaW5nLCBuYW1lOiBzdHJpbmcpOiBQcm9taXNlPEFjY291bnRTdW1tYXJ5IHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IHJlcyA9IGF3YWl0IGNsaWVudC5nZXQ8dW5rbm93bj4oYC9hcGkvb3JnYW5pemF0aW9uLyR7b3JnSWR9L3NlcnZpY2UtYWNjb3VudHNgKTtcbiAgY29uc3QgYWNjb3VudHMgPSB1bndyYXA8eyBzZXJ2aWNlQWNjb3VudHM/OiBBY2NvdW50U3VtbWFyeVtdIH0+KHJlcyk/LnNlcnZpY2VBY2NvdW50cyA/PyBbXTtcbiAgcmV0dXJuIGFjY291bnRzLmZpbmQoKGEpID0+IGEubmFtZSA9PT0gbmFtZSk7XG59XG5cbi8qKlxuICogQ3JlYXRlIHRoZSBhY2NvdW50IGlmIGl0IGlzbid0IHRoZXJlIHlldCwgYW5kIHJldHVybiBpdHMgaWQuIElERU1QT1RFTlQ6IGFcbiAqIHJlLXJ1biByZXVzZXMgdGhlIGV4aXN0aW5nIGFjY291bnQgKGluY2x1ZGluZyB0aGUgNDA5IHJhY2Ugd2hlcmUgdHdvIHJ1bnNcbiAqIGNyZWF0ZSBpdCBhdCBvbmNlKSwgYW5kIG5ldmVyIHJlLWdyYW50cyBSb2xlcyDigJQgYW4gb3BlcmF0b3Igd2hvIG5hcnJvd2VkIHRoZVxuICogYWNjb3VudCdzIFJvbGVzIGJ5IGhhbmQgbXVzdCBub3QgaGF2ZSB0aGF0IHVuZG9uZSBieSB0aGUgbmV4dCBgc3RvcmUtdG9rZW5gLlxuICovXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVBY2NvdW50KG9wdHM6IFByb3Zpc2lvbktleU9wdGlvbnMsIG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBleGlzdGluZyA9IGF3YWl0IGZpbmRBY2NvdW50KG9wdHMuY2xpZW50LCBvcmdJZCwgb3B0cy5hY2NvdW50TmFtZSk7XG4gIGlmIChleGlzdGluZykge1xuICAgIHByaW50SW5mbygnUmV1c2luZyB0aGUgZXhpc3Rpbmcgc2VydmljZSBhY2NvdW50JywgeyBhY2NvdW50OiBvcHRzLmFjY291bnROYW1lLCBpZDogZXhpc3RpbmcuaWQgfSk7XG4gICAgcmV0dXJuIGV4aXN0aW5nLmlkO1xuICB9XG5cbiAgY29uc3Qgcm9sZUlkcyA9IG9wdHMucm9sZXMgPT09ICdhZG1pbicgPyBbYXdhaXQgcmVzb2x2ZUFkbWluUm9sZUlkKG9wdHMuY2xpZW50LCBvcmdJZCldIDogW107XG4gIHRyeSB7XG4gICAgY29uc3QgcmVzID0gYXdhaXQgb3B0cy5jbGllbnQucG9zdDx1bmtub3duPihcbiAgICAgIGAvYXBpL29yZ2FuaXphdGlvbi8ke29yZ0lkfS9zZXJ2aWNlLWFjY291bnRzYCxcbiAgICAgIHsgbmFtZTogb3B0cy5hY2NvdW50TmFtZSwgZGVzY3JpcHRpb246IG9wdHMuZGVzY3JpcHRpb24sIHJvbGVJZHMgfSxcbiAgICAgIHsgW1NURVBfVVBfSEVBREVSXTogYXdhaXQgc3RlcFVwKG9wdHMuY2xpZW50LCBvcHRzLnBhc3N3b3JkKSB9LFxuICAgICk7XG4gICAgY29uc3QgYWNjb3VudCA9IHVud3JhcDx7IHNlcnZpY2VBY2NvdW50PzogeyBpZD86IHN0cmluZyB9IH0+KHJlcyk/LnNlcnZpY2VBY2NvdW50O1xuICAgIGlmICghYWNjb3VudD8uaWQpIHRocm93IG5ldyBFcnJvcignc2VydmljZS1hY2NvdW50IGNyZWF0ZSByZXR1cm5lZCBubyBpZCcpO1xuICAgIHByaW50U3VjY2VzcyhgQ3JlYXRlZCB0aGUgJyR7b3B0cy5hY2NvdW50TmFtZX0nIHNlcnZpY2UgYWNjb3VudGApO1xuICAgIHJldHVybiBhY2NvdW50LmlkO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBpZiAoc3RhdHVzT2YoZXJyKSA9PT0gNDA5KSB7XG4gICAgICBjb25zdCByYWNlZCA9IGF3YWl0IGZpbmRBY2NvdW50KG9wdHMuY2xpZW50LCBvcmdJZCwgb3B0cy5hY2NvdW50TmFtZSk7XG4gICAgICBpZiAocmFjZWQpIHJldHVybiByYWNlZC5pZDtcbiAgICB9XG4gICAgdGhyb3cgZXJyO1xuICB9XG59XG5cbi8qKiBSZXZva2Ugb25lIG9mIGFuIGFjY291bnQncyBrZXlzLiBCZXN0LWVmZm9ydCBieSBjb250cmFjdCDigJQgc2VlIHRoZSBjYWxsIHNpdGVzLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJldm9rZVNlcnZpY2VBY2NvdW50S2V5KFxuICBjbGllbnQ6IEFwaUNsaWVudCxcbiAgcGFzc3dvcmQ6IHN0cmluZyxcbiAgb3JnSWQ6IHN0cmluZyxcbiAgYWNjb3VudElkOiBzdHJpbmcsXG4gIGtleUlkOiBzdHJpbmcsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgY2xpZW50LmRlbGV0ZShcbiAgICBgL2FwaS9vcmdhbml6YXRpb24vJHtvcmdJZH0vc2VydmljZS1hY2NvdW50cy8ke2FjY291bnRJZH0va2V5cy8ke2tleUlkfWAsXG4gICAgeyBbU1RFUF9VUF9IRUFERVJdOiBhd2FpdCBzdGVwVXAoY2xpZW50LCBwYXNzd29yZCkgfSxcbiAgKTtcbn1cblxuLyoqXG4gKiBJc3N1ZSBhIGtleSwgc2VsZi1oZWFsaW5nIHBhc3QgdGhlIHBlci1hY2NvdW50IGFjdGl2ZS1rZXkgY2FwOiBhdCB0aGUgY2FwIHRoZVxuICogT0xERVNUIGFjdGl2ZSBrZXkgaXMgcmV0aXJlZCBhbmQgdGhlIG1pbnQgcmV0cmllZCBvbmNlLiBUaGUgY2FwIGV4aXN0cyB0byBib3VuZFxuICogYSBjb21wcm9taXNlLCBub3QgdG8gbWFrZSBwcm92aXNpb25pbmcgZmFpbCwgYW5kIHRoZSBjcmVkZW50aWFsIGEgcmUtcnVuIGlzXG4gKiByZXBsYWNpbmcgaXMgdGhlIHZlcnkgdGhpbmcgdGhhdCBzaG91bGQgZ28uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGlzc3VlS2V5KFxuICBvcHRzOiBQcm92aXNpb25LZXlPcHRpb25zLFxuICBvcmdJZDogc3RyaW5nLFxuICBhY2NvdW50SWQ6IHN0cmluZyxcbik6IFByb21pc2U8eyBrZXk6IHN0cmluZzsgYWNjZXNzS2V5OiB7IGlkOiBzdHJpbmc7IGV4cGlyZXNBdDogc3RyaW5nOyBzY29wZTogc3RyaW5nIHwgbnVsbCB9IH0+IHtcbiAgY29uc3QgYm9keSA9IHtcbiAgICBuYW1lOiBvcHRzLmtleU5hbWUsXG4gICAgZXhwaXJlc0luOiBvcHRzLmV4cGlyZXNJblNlY29uZHMsXG4gICAgLi4uKG9wdHMuc2NvcGUgPyB7IHNjb3BlOiBvcHRzLnNjb3BlIH0gOiB7fSksXG4gIH07XG4gIGNvbnN0IG1pbnQgPSBhc3luYyAoKSA9PiB1bndyYXA8eyBrZXk6IHN0cmluZzsgYWNjZXNzS2V5OiB7IGlkOiBzdHJpbmc7IGV4cGlyZXNBdDogc3RyaW5nOyBzY29wZTogc3RyaW5nIHwgbnVsbCB9IH0+KFxuICAgIGF3YWl0IG9wdHMuY2xpZW50LnBvc3Q8dW5rbm93bj4oXG4gICAgICBgL2FwaS9vcmdhbml6YXRpb24vJHtvcmdJZH0vc2VydmljZS1hY2NvdW50cy8ke2FjY291bnRJZH0va2V5c2AsXG4gICAgICBib2R5LFxuICAgICAgeyBbU1RFUF9VUF9IRUFERVJdOiBhd2FpdCBzdGVwVXAob3B0cy5jbGllbnQsIG9wdHMucGFzc3dvcmQpIH0sXG4gICAgKSxcbiAgKTtcblxuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBtaW50KCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmIChzdGF0dXNPZihlcnIpICE9PSA0MDkgJiYgZXJyb3JDb2RlT2YoZXJyKSAhPT0gJ1NBX0tFWV9MSU1JVCcpIHRocm93IGVycjtcbiAgICBjb25zdCBhY2NvdW50ID0gYXdhaXQgZmluZEFjY291bnQob3B0cy5jbGllbnQsIG9yZ0lkLCBvcHRzLmFjY291bnROYW1lKTtcbiAgICBjb25zdCBvbGRlc3QgPSAoYWNjb3VudD8ua2V5cyA/PyBbXSlcbiAgICAgIC5maWx0ZXIoKGspID0+IGsuc3RhdHVzID09PSAnYWN0aXZlJylcbiAgICAgIC5zb3J0KChhLCBiKSA9PiBhLmNyZWF0ZWRBdC5sb2NhbGVDb21wYXJlKGIuY3JlYXRlZEF0KSlbMF07XG4gICAgaWYgKCFvbGRlc3QpIHRocm93IGVycjtcbiAgICBwcmludFdhcm5pbmcoYFNlcnZpY2UgYWNjb3VudCAnJHtvcHRzLmFjY291bnROYW1lfScgaXMgYXQgaXRzIGFjdGl2ZS1rZXkgbGltaXQg4oCUIHJldGlyaW5nIGl0cyBvbGRlc3Qga2V5ICgke29sZGVzdC5pZH0pLmApO1xuICAgIGF3YWl0IHJldm9rZVNlcnZpY2VBY2NvdW50S2V5KG9wdHMuY2xpZW50LCBvcHRzLnBhc3N3b3JkLCBvcmdJZCwgYWNjb3VudElkLCBvbGRlc3QuaWQpO1xuICAgIHJldHVybiBtaW50KCk7XG4gIH1cbn1cblxuLyoqXG4gKiBFbnN1cmUgdGhlIG5hbWVkIHNlcnZpY2UgYWNjb3VudCBleGlzdHMgYW5kIGlzc3VlIGl0IGEgZnJlc2gga2V5LlxuICpcbiAqIERlbGliZXJhdGVseSBkb2VzIE5PVCByZXZva2UgYW55dGhpbmcgdGhlIGNhbGxlciB3YXMgcHJldmlvdXNseSBob2xkaW5nOiB0aGVcbiAqIGNhbGxlciBzdG9yZXMgdGhlIG5ldyBrZXkgZmlyc3QgYW5kIHJldGlyZXMgdGhlIG9sZCBvbmUgYWZ0ZXJ3YXJkcyAoc2VlXG4gKiBgc3RvcmUtdG9rZW5gKSwgc28gYSBmYWlsdXJlIGF0IGFueSBwb2ludCBsZWF2ZXMgYSB3b3JraW5nIGNyZWRlbnRpYWwgaW4gdGhlXG4gKiBzZWNyZXQgcmF0aGVyIHRoYW4gYW4gZW1wdHkgb25lLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJvdmlzaW9uU2VydmljZUFjY291bnRLZXkob3B0czogUHJvdmlzaW9uS2V5T3B0aW9ucyk6IFByb21pc2U8UHJvdmlzaW9uZWRLZXk+IHtcbiAgY29uc3Qgb3JnYW5pemF0aW9uSWQgPSBhd2FpdCByZXNvbHZlT3JnYW5pemF0aW9uSWQob3B0cy5jbGllbnQpO1xuICBjb25zdCBzZXJ2aWNlQWNjb3VudElkID0gYXdhaXQgZW5zdXJlQWNjb3VudChvcHRzLCBvcmdhbml6YXRpb25JZCk7XG4gIGNvbnN0IHsga2V5LCBhY2Nlc3NLZXkgfSA9IGF3YWl0IGlzc3VlS2V5KG9wdHMsIG9yZ2FuaXphdGlvbklkLCBzZXJ2aWNlQWNjb3VudElkKTtcbiAgcmV0dXJuIHtcbiAgICBrZXksXG4gICAga2V5SWQ6IGFjY2Vzc0tleS5pZCxcbiAgICBzZXJ2aWNlQWNjb3VudElkLFxuICAgIHNlcnZpY2VBY2NvdW50TmFtZTogb3B0cy5hY2NvdW50TmFtZSxcbiAgICBvcmdhbml6YXRpb25JZCxcbiAgICBleHBpcmVzQXQ6IGFjY2Vzc0tleS5leHBpcmVzQXQsXG4gICAgc2NvcGU6IGFjY2Vzc0tleS5zY29wZSA/PyBudWxsLFxuICB9O1xufVxuIl19
|
package/package.json
CHANGED
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
45
45
|
"yaml": "2.9.0",
|
|
46
46
|
"zod": "4.4.3",
|
|
47
|
-
"@pipeline-builder/
|
|
48
|
-
"@pipeline-builder/pipeline-core": "4.1.
|
|
49
|
-
"@pipeline-builder/
|
|
47
|
+
"@pipeline-builder/ai-core": "4.1.5",
|
|
48
|
+
"@pipeline-builder/pipeline-core": "4.1.6",
|
|
49
|
+
"@pipeline-builder/api-core": "4.1.5"
|
|
50
50
|
},
|
|
51
51
|
"keywords": [
|
|
52
52
|
"ci-cd",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"access": "public",
|
|
102
102
|
"registry": "https://registry.npmjs.org/"
|
|
103
103
|
},
|
|
104
|
-
"version": "4.1.
|
|
104
|
+
"version": "4.1.6",
|
|
105
105
|
"bugs": {
|
|
106
106
|
"url": "https://github.com/mwashburn160/pipeline-builder/issues"
|
|
107
107
|
},
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Check if auth attempts for this identifier are currently rate-limited.
|
|
3
|
-
* @returns null if allowed, or a message string if blocked.
|
|
4
|
-
*/
|
|
5
|
-
export declare function checkAuthRateLimit(identifier?: string, baseUrl?: string): string | null;
|
|
6
|
-
/**
|
|
7
|
-
* Record a successful auth for this identifier — clears its failure counter.
|
|
8
|
-
*/
|
|
9
|
-
export declare function recordAuthSuccess(identifier?: string, baseUrl?: string): void;
|
|
10
|
-
/**
|
|
11
|
-
* Record a failed auth attempt for this identifier. After MAX_FAILURES, locks out
|
|
12
|
-
* that identifier for COOLDOWN_MS.
|
|
13
|
-
*/
|
|
14
|
-
export declare function recordAuthFailure(identifier?: string, baseUrl?: string): void;
|
|
15
|
-
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAgHA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyBvF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAM7E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAgB7E"}
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import crypto from 'crypto';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
import os from 'os';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
/**
|
|
8
|
-
* Simple file-based rate limiter for auth operations.
|
|
9
|
-
* Tracks failed attempts and enforces a cooldown period after too many failures.
|
|
10
|
-
* State is persisted in a temp file so it survives across CLI invocations.
|
|
11
|
-
*
|
|
12
|
-
* State is keyed per (baseUrl, identifier) so a failed login for one account does
|
|
13
|
-
* NOT lock out another account on a shared workstation / CI host. Calls without an
|
|
14
|
-
* identifier fall back to a shared `_default` bucket (coarse anti-bruteforce).
|
|
15
|
-
*/
|
|
16
|
-
const STATE_FILE = path.join(os.tmpdir(), '.pipeline-manager-auth-state.json');
|
|
17
|
-
// Directory-as-mutex guarding the read-modify-write. `mkdir` is atomic on every
|
|
18
|
-
// platform, so concurrent CLI invocations serialize on it instead of racing (a
|
|
19
|
-
// lost increment would under-count toward lockout — see withLock).
|
|
20
|
-
const LOCK_DIR = `${STATE_FILE}.lock`;
|
|
21
|
-
const MAX_FAILURES = 5;
|
|
22
|
-
const COOLDOWN_MS = 60_000; // 1 minute
|
|
23
|
-
const PRUNE_MS = 60 * 60_000; // drop buckets idle for >1h to bound file growth
|
|
24
|
-
const LOCK_STALE_MS = 5_000; // reclaim a lock left by a crashed process
|
|
25
|
-
const LOCK_WAIT_MS = 1_000; // give up waiting after this (best-effort: proceed unlocked)
|
|
26
|
-
const LOCK_RETRY_MS = 15; // spin interval while the lock is held
|
|
27
|
-
const EMPTY = { failures: 0, lastFailure: 0, lockedUntil: 0 };
|
|
28
|
-
/** Stable, non-reversible bucket key for a (baseUrl, identifier) pair. */
|
|
29
|
-
function keyFor(identifier, baseUrl) {
|
|
30
|
-
if (!identifier)
|
|
31
|
-
return '_default';
|
|
32
|
-
return crypto.createHash('sha256').update(`${baseUrl ?? ''}\n${identifier}`).digest('hex').slice(0, 16);
|
|
33
|
-
}
|
|
34
|
-
function readMap() {
|
|
35
|
-
try {
|
|
36
|
-
if (fs.existsSync(STATE_FILE)) {
|
|
37
|
-
const parsed = JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
|
|
38
|
-
if (parsed && typeof parsed === 'object')
|
|
39
|
-
return parsed;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
catch { /* ignore corrupt state */ }
|
|
43
|
-
return {};
|
|
44
|
-
}
|
|
45
|
-
function writeMap(map) {
|
|
46
|
-
const now = Date.now();
|
|
47
|
-
// Prune idle buckets so the file doesn't grow unbounded across many identifiers.
|
|
48
|
-
for (const [k, s] of Object.entries(map)) {
|
|
49
|
-
if (s.lockedUntil <= now && now - s.lastFailure > PRUNE_MS)
|
|
50
|
-
delete map[k];
|
|
51
|
-
}
|
|
52
|
-
try {
|
|
53
|
-
// Write to a per-process temp file then rename: rename is atomic on the same
|
|
54
|
-
// filesystem, so a concurrent reader never observes a torn/half-written file.
|
|
55
|
-
const tmp = `${STATE_FILE}.${process.pid}.tmp`;
|
|
56
|
-
fs.writeFileSync(tmp, JSON.stringify(map), { mode: 0o600 });
|
|
57
|
-
fs.renameSync(tmp, STATE_FILE);
|
|
58
|
-
}
|
|
59
|
-
catch { /* best-effort */ }
|
|
60
|
-
}
|
|
61
|
-
/** Block the current thread for `ms` without a busy-wait (CLI-only, short waits). */
|
|
62
|
-
function sleep(ms) {
|
|
63
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Run `fn` while holding a cross-process advisory lock so the read-modify-write in
|
|
67
|
-
* recordAuthFailure/Success can't lose an update to a concurrent CLI invocation
|
|
68
|
-
* (the TOCTOU that let parallel runs under-count toward lockout). Best-effort: if
|
|
69
|
-
* the lock can't be acquired within LOCK_WAIT_MS we proceed anyway rather than
|
|
70
|
-
* block the user — server-side rate limiting remains the real enforcement.
|
|
71
|
-
*/
|
|
72
|
-
function withLock(fn) {
|
|
73
|
-
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
74
|
-
let held = false;
|
|
75
|
-
while (Date.now() < deadline) {
|
|
76
|
-
try {
|
|
77
|
-
fs.mkdirSync(LOCK_DIR);
|
|
78
|
-
held = true;
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
// Held elsewhere — reclaim it if it's stale (owner crashed without cleanup),
|
|
83
|
-
// otherwise wait a beat and retry.
|
|
84
|
-
try {
|
|
85
|
-
if (Date.now() - fs.statSync(LOCK_DIR).mtimeMs > LOCK_STALE_MS) {
|
|
86
|
-
fs.rmdirSync(LOCK_DIR);
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch { /* lock vanished between calls — just retry */ }
|
|
91
|
-
sleep(LOCK_RETRY_MS);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
try {
|
|
95
|
-
return fn();
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
98
|
-
if (held) {
|
|
99
|
-
try {
|
|
100
|
-
fs.rmdirSync(LOCK_DIR);
|
|
101
|
-
}
|
|
102
|
-
catch { /* already gone */ }
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Check if auth attempts for this identifier are currently rate-limited.
|
|
108
|
-
* @returns null if allowed, or a message string if blocked.
|
|
109
|
-
*/
|
|
110
|
-
export function checkAuthRateLimit(identifier, baseUrl) {
|
|
111
|
-
const key = keyFor(identifier, baseUrl);
|
|
112
|
-
const map = readMap();
|
|
113
|
-
const state = map[key] ?? EMPTY;
|
|
114
|
-
const now = Date.now();
|
|
115
|
-
if (state.lockedUntil > now) {
|
|
116
|
-
const waitSec = Math.ceil((state.lockedUntil - now) / 1000);
|
|
117
|
-
return `Too many failed login attempts. Try again in ${waitSec}s.`;
|
|
118
|
-
}
|
|
119
|
-
// Reset this bucket once the cooldown window has passed. Re-read under the lock
|
|
120
|
-
// so we don't clobber a concurrent recordAuthFailure for another bucket.
|
|
121
|
-
if (state.lastFailure !== 0 && now - state.lastFailure > COOLDOWN_MS) {
|
|
122
|
-
withLock(() => {
|
|
123
|
-
const m = readMap();
|
|
124
|
-
const s = m[key];
|
|
125
|
-
if (s && s.lastFailure !== 0 && Date.now() - s.lastFailure > COOLDOWN_MS) {
|
|
126
|
-
delete m[key];
|
|
127
|
-
writeMap(m);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Record a successful auth for this identifier — clears its failure counter.
|
|
135
|
-
*/
|
|
136
|
-
export function recordAuthSuccess(identifier, baseUrl) {
|
|
137
|
-
withLock(() => {
|
|
138
|
-
const map = readMap();
|
|
139
|
-
delete map[keyFor(identifier, baseUrl)];
|
|
140
|
-
writeMap(map);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Record a failed auth attempt for this identifier. After MAX_FAILURES, locks out
|
|
145
|
-
* that identifier for COOLDOWN_MS.
|
|
146
|
-
*/
|
|
147
|
-
export function recordAuthFailure(identifier, baseUrl) {
|
|
148
|
-
const key = keyFor(identifier, baseUrl);
|
|
149
|
-
// Read-modify-write under the lock: a concurrent CLI invocation must not read the
|
|
150
|
-
// same pre-increment count and overwrite this one (which would under-count).
|
|
151
|
-
withLock(() => {
|
|
152
|
-
const map = readMap();
|
|
153
|
-
const now = Date.now();
|
|
154
|
-
const state = { ...(map[key] ?? EMPTY) };
|
|
155
|
-
state.failures += 1;
|
|
156
|
-
state.lastFailure = now;
|
|
157
|
-
if (state.failures >= MAX_FAILURES) {
|
|
158
|
-
state.lockedUntil = now + COOLDOWN_MS;
|
|
159
|
-
}
|
|
160
|
-
map[key] = state;
|
|
161
|
-
writeMap(map);
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3JhdGUtbGltaXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUM1QixPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDcEIsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3BCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUV4Qjs7Ozs7Ozs7R0FRRztBQUVILE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLG1DQUFtQyxDQUFDLENBQUM7QUFDL0UsZ0ZBQWdGO0FBQ2hGLCtFQUErRTtBQUMvRSxtRUFBbUU7QUFDbkUsTUFBTSxRQUFRLEdBQUcsR0FBRyxVQUFVLE9BQU8sQ0FBQztBQUN0QyxNQUFNLFlBQVksR0FBRyxDQUFDLENBQUM7QUFDdkIsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLENBQUMsV0FBVztBQUN2QyxNQUFNLFFBQVEsR0FBRyxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsaURBQWlEO0FBQy9FLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxDQUFDLDJDQUEyQztBQUN4RSxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsQ0FBQyw2REFBNkQ7QUFDekYsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFDLENBQUMsdUNBQXVDO0FBVWpFLE1BQU0sS0FBSyxHQUFjLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQztBQUV6RSwwRUFBMEU7QUFDMUUsU0FBUyxNQUFNLENBQUMsVUFBbUIsRUFBRSxPQUFnQjtJQUNuRCxJQUFJLENBQUMsVUFBVTtRQUFFLE9BQU8sVUFBVSxDQUFDO0lBQ25DLE9BQU8s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R0FBRyxDQUFDO1FBQ3hCLElBQUksS0FBSyxDQUFDLFFBQVEsSUFBSSxZQUFZLEVBQUUsQ0FBQztZQUNuQyxLQUFLLENBQUMsV0FBVyxHQUFHLEdBQUcsR0FBRyxXQUFXLENBQUM7UUFDeEMsQ0FBQztRQUNELEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7UUFDakIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2hCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xuaW1wb3J0IG9zIGZyb20gJ29zJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuXG4vKipcbiAqIFNpbXBsZSBmaWxlLWJhc2VkIHJhdGUgbGltaXRlciBmb3IgYXV0aCBvcGVyYXRpb25zLlxuICogVHJhY2tzIGZhaWxlZCBhdHRlbXB0cyBhbmQgZW5mb3JjZXMgYSBjb29sZG93biBwZXJpb2QgYWZ0ZXIgdG9vIG1hbnkgZmFpbHVyZXMuXG4gKiBTdGF0ZSBpcyBwZXJzaXN0ZWQgaW4gYSB0ZW1wIGZpbGUgc28gaXQgc3Vydml2ZXMgYWNyb3NzIENMSSBpbnZvY2F0aW9ucy5cbiAqXG4gKiBTdGF0ZSBpcyBrZXllZCBwZXIgKGJhc2VVcmwsIGlkZW50aWZpZXIpIHNvIGEgZmFpbGVkIGxvZ2luIGZvciBvbmUgYWNjb3VudCBkb2VzXG4gKiBOT1QgbG9jayBvdXQgYW5vdGhlciBhY2NvdW50IG9uIGEgc2hhcmVkIHdvcmtzdGF0aW9uIC8gQ0kgaG9zdC4gQ2FsbHMgd2l0aG91dCBhblxuICogaWRlbnRpZmllciBmYWxsIGJhY2sgdG8gYSBzaGFyZWQgYF9kZWZhdWx0YCBidWNrZXQgKGNvYXJzZSBhbnRpLWJydXRlZm9yY2UpLlxuICovXG5cbmNvbnN0IFNUQVRFX0ZJTEUgPSBwYXRoLmpvaW4ob3MudG1wZGlyKCksICcucGlwZWxpbmUtbWFuYWdlci1hdXRoLXN0YXRlLmpzb24nKTtcbi8vIERpcmVjdG9yeS1hcy1tdXRleCBndWFyZGluZyB0aGUgcmVhZC1tb2RpZnktd3JpdGUuIGBta2RpcmAgaXMgYXRvbWljIG9uIGV2ZXJ5XG4vLyBwbGF0Zm9ybSwgc28gY29uY3VycmVudCBDTEkgaW52b2NhdGlvbnMgc2VyaWFsaXplIG9uIGl0IGluc3RlYWQgb2YgcmFjaW5nIChhXG4vLyBsb3N0IGluY3JlbWVudCB3b3VsZCB1bmRlci1jb3VudCB0b3dhcmQgbG9ja291dCDigJQgc2VlIHdpdGhMb2NrKS5cbmNvbnN0IExPQ0tfRElSID0gYCR7U1RBVEVfRklMRX0ubG9ja2A7XG5jb25zdCBNQVhfRkFJTFVSRVMgPSA1O1xuY29uc3QgQ09PTERPV05fTVMgPSA2MF8wMDA7IC8vIDEgbWludXRlXG5jb25zdCBQUlVORV9NUyA9IDYwICogNjBfMDAwOyAvLyBkcm9wIGJ1Y2tldHMgaWRsZSBmb3IgPjFoIHRvIGJvdW5kIGZpbGUgZ3Jvd3RoXG5jb25zdCBMT0NLX1NUQUxFX01TID0gNV8wMDA7IC8vIHJlY2xhaW0gYSBsb2NrIGxlZnQgYnkgYSBjcmFzaGVkIHByb2Nlc3NcbmNvbnN0IExPQ0tfV0FJVF9NUyA9IDFfMDAwOyAvLyBnaXZlIHVwIHdhaXRpbmcgYWZ0ZXIgdGhpcyAoYmVzdC1lZmZvcnQ6IHByb2NlZWQgdW5sb2NrZWQpXG5jb25zdCBMT0NLX1JFVFJZX01TID0gMTU7IC8vIHNwaW4gaW50ZXJ2YWwgd2hpbGUgdGhlIGxvY2sgaXMgaGVsZFxuXG5pbnRlcmZhY2UgQXV0aFN0YXRlIHtcbiAgZmFpbHVyZXM6IG51bWJlcjtcbiAgbGFzdEZhaWx1cmU6IG51bWJlcjtcbiAgbG9ja2VkVW50aWw6IG51bWJlcjtcbn1cblxudHlwZSBTdGF0ZU1hcCA9IFJlY29yZDxzdHJpbmcsIEF1dGhTdGF0ZT47XG5cbmNvbnN0IEVNUFRZOiBBdXRoU3RhdGUgPSB7IGZhaWx1cmVzOiAwLCBsYXN0RmFpbHVyZTogMCwgbG9ja2VkVW50aWw6IDAgfTtcblxuLyoqIFN0YWJsZSwgbm9uLXJldmVyc2libGUgYnVja2V0IGtleSBmb3IgYSAoYmFzZVVybCwgaWRlbnRpZmllcikgcGFpci4gKi9cbmZ1bmN0aW9uIGtleUZvcihpZGVudGlmaWVyPzogc3RyaW5nLCBiYXNlVXJsPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKCFpZGVudGlmaWVyKSByZXR1cm4gJ19kZWZhdWx0JztcbiAgcmV0dXJuIGNyeXB0by5jcmVhdGVIYXNoKCdzaGEyNTYnKS51cGRhdGUoYCR7YmFzZVVybCA/PyAnJ31cXG4ke2lkZW50aWZpZXJ9YCkuZGlnZXN0KCdoZXgnKS5zbGljZSgwLCAxNik7XG59XG5cbmZ1bmN0aW9uIHJlYWRNYXAoKTogU3RhdGVNYXAge1xuICB0cnkge1xuICAgIGlmIChmcy5leGlzdHNTeW5jKFNUQVRFX0ZJTEUpKSB7XG4gICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhTVEFURV9GSUxFLCAndXRmLTgnKSkgYXMgdW5rbm93bjtcbiAgICAgIGlmIChwYXJzZWQgJiYgdHlwZW9mIHBhcnNlZCA9PT0gJ29iamVjdCcpIHJldHVybiBwYXJzZWQgYXMgU3RhdGVNYXA7XG4gICAgfVxuICB9IGNhdGNoIHsgLyogaWdub3JlIGNvcnJ1cHQgc3RhdGUgKi8gfVxuICByZXR1cm4ge307XG59XG5cbmZ1bmN0aW9uIHdyaXRlTWFwKG1hcDogU3RhdGVNYXApOiB2b2lkIHtcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgLy8gUHJ1bmUgaWRsZSBidWNrZXRzIHNvIHRoZSBmaWxlIGRvZXNuJ3QgZ3JvdyB1bmJvdW5kZWQgYWNyb3NzIG1hbnkgaWRlbnRpZmllcnMuXG4gIGZvciAoY29uc3QgW2ssIHNdIG9mIE9iamVjdC5lbnRyaWVzKG1hcCkpIHtcbiAgICBpZiAocy5sb2NrZWRVbnRpbCA8PSBub3cgJiYgbm93IC0gcy5sYXN0RmFpbHVyZSA+IFBSVU5FX01TKSBkZWxldGUgbWFwW2tdO1xuICB9XG4gIHRyeSB7XG4gICAgLy8gV3JpdGUgdG8gYSBwZXItcHJvY2VzcyB0ZW1wIGZpbGUgdGhlbiByZW5hbWU6IHJlbmFtZSBpcyBhdG9taWMgb24gdGhlIHNhbWVcbiAgICAvLyBmaWxlc3lzdGVtLCBzbyBhIGNvbmN1cnJlbnQgcmVhZGVyIG5ldmVyIG9ic2VydmVzIGEgdG9ybi9oYWxmLXdyaXR0ZW4gZmlsZS5cbiAgICBjb25zdCB0bXAgPSBgJHtTVEFURV9GSUxFfS4ke3Byb2Nlc3MucGlkfS50bXBgO1xuICAgIGZzLndyaXRlRmlsZVN5bmModG1wLCBKU09OLnN0cmluZ2lmeShtYXApLCB7IG1vZGU6IDBvNjAwIH0pO1xuICAgIGZzLnJlbmFtZVN5bmModG1wLCBTVEFURV9GSUxFKTtcbiAgfSBjYXRjaCB7IC8qIGJlc3QtZWZmb3J0ICovIH1cbn1cblxuLyoqIEJsb2NrIHRoZSBjdXJyZW50IHRocmVhZCBmb3IgYG1zYCB3aXRob3V0IGEgYnVzeS13YWl0IChDTEktb25seSwgc2hvcnQgd2FpdHMpLiAqL1xuZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcik6IHZvaWQge1xuICBBdG9taWNzLndhaXQobmV3IEludDMyQXJyYXkobmV3IFNoYXJlZEFycmF5QnVmZmVyKDQpKSwgMCwgMCwgbXMpO1xufVxuXG4vKipcbiAqIFJ1biBgZm5gIHdoaWxlIGhvbGRpbmcgYSBjcm9zcy1wcm9jZXNzIGFkdmlzb3J5IGxvY2sgc28gdGhlIHJlYWQtbW9kaWZ5LXdyaXRlIGluXG4gKiByZWNvcmRBdXRoRmFpbHVyZS9TdWNjZXNzIGNhbid0IGxvc2UgYW4gdXBkYXRlIHRvIGEgY29uY3VycmVudCBDTEkgaW52b2NhdGlvblxuICogKHRoZSBUT0NUT1UgdGhhdCBsZXQgcGFyYWxsZWwgcnVucyB1bmRlci1jb3VudCB0b3dhcmQgbG9ja291dCkuIEJlc3QtZWZmb3J0OiBpZlxuICogdGhlIGxvY2sgY2FuJ3QgYmUgYWNxdWlyZWQgd2l0aGluIExPQ0tfV0FJVF9NUyB3ZSBwcm9jZWVkIGFueXdheSByYXRoZXIgdGhhblxuICogYmxvY2sgdGhlIHVzZXIg4oCUIHNlcnZlci1zaWRlIHJhdGUgbGltaXRpbmcgcmVtYWlucyB0aGUgcmVhbCBlbmZvcmNlbWVudC5cbiAqL1xuZnVuY3Rpb24gd2l0aExvY2s8VD4oZm46ICgpID0+IFQpOiBUIHtcbiAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgTE9DS19XQUlUX01TO1xuICBsZXQgaGVsZCA9IGZhbHNlO1xuICB3aGlsZSAoRGF0ZS5ub3coKSA8IGRlYWRsaW5lKSB7XG4gICAgdHJ5IHtcbiAgICAgIGZzLm1rZGlyU3luYyhMT0NLX0RJUik7XG4gICAgICBoZWxkID0gdHJ1ZTtcbiAgICAgIGJyZWFrO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gSGVsZCBlbHNld2hlcmUg4oCUIHJlY2xhaW0gaXQgaWYgaXQncyBzdGFsZSAob3duZXIgY3Jhc2hlZCB3aXRob3V0IGNsZWFudXApLFxuICAgICAgLy8gb3RoZXJ3aXNlIHdhaXQgYSBiZWF0IGFuZCByZXRyeS5cbiAgICAgIHRyeSB7XG4gICAgICAgIGlmIChEYXRlLm5vdygpIC0gZnMuc3RhdFN5bmMoTE9DS19ESVIpLm10aW1lTXMgPiBMT0NLX1NUQUxFX01TKSB7XG4gICAgICAgICAgZnMucm1kaXJTeW5jKExPQ0tfRElSKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCB7IC8qIGxvY2sgdmFuaXNoZWQgYmV0d2VlbiBjYWxscyDigJQganVzdCByZXRyeSAqLyB9XG4gICAgICBzbGVlcChMT0NLX1JFVFJZX01TKTtcbiAgICB9XG4gIH1cbiAgdHJ5IHtcbiAgICByZXR1cm4gZm4oKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBpZiAoaGVsZCkge1xuICAgICAgdHJ5IHsgZnMucm1kaXJTeW5jKExPQ0tfRElSKTsgfSBjYXRjaCB7IC8qIGFscmVhZHkgZ29uZSAqLyB9XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgYXV0aCBhdHRlbXB0cyBmb3IgdGhpcyBpZGVudGlmaWVyIGFyZSBjdXJyZW50bHkgcmF0ZS1saW1pdGVkLlxuICogQHJldHVybnMgbnVsbCBpZiBhbGxvd2VkLCBvciBhIG1lc3NhZ2Ugc3RyaW5nIGlmIGJsb2NrZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGVja0F1dGhSYXRlTGltaXQoaWRlbnRpZmllcj86IHN0cmluZywgYmFzZVVybD86IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBrZXkgPSBrZXlGb3IoaWRlbnRpZmllciwgYmFzZVVybCk7XG4gIGNvbnN0IG1hcCA9IHJlYWRNYXAoKTtcbiAgY29uc3Qgc3RhdGUgPSBtYXBba2V5XSA/PyBFTVBUWTtcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcblxuICBpZiAoc3RhdGUubG9ja2VkVW50aWwgPiBub3cpIHtcbiAgICBjb25zdCB3YWl0U2VjID0gTWF0aC5jZWlsKChzdGF0ZS5sb2NrZWRVbnRpbCAtIG5vdykgLyAxMDAwKTtcbiAgICByZXR1cm4gYFRvbyBtYW55IGZhaWxlZCBsb2dpbiBhdHRlbXB0cy4gVHJ5IGFnYWluIGluICR7d2FpdFNlY31zLmA7XG4gIH1cblxuICAvLyBSZXNldCB0aGlzIGJ1Y2tldCBvbmNlIHRoZSBjb29sZG93biB3aW5kb3cgaGFzIHBhc3NlZC4gUmUtcmVhZCB1bmRlciB0aGUgbG9ja1xuICAvLyBzbyB3ZSBkb24ndCBjbG9iYmVyIGEgY29uY3VycmVudCByZWNvcmRBdXRoRmFpbHVyZSBmb3IgYW5vdGhlciBidWNrZXQuXG4gIGlmIChzdGF0ZS5sYXN0RmFpbHVyZSAhPT0gMCAmJiBub3cgLSBzdGF0ZS5sYXN0RmFpbHVyZSA+IENPT0xET1dOX01TKSB7XG4gICAgd2l0aExvY2soKCkgPT4ge1xuICAgICAgY29uc3QgbSA9IHJlYWRNYXAoKTtcbiAgICAgIGNvbnN0IHMgPSBtW2tleV07XG4gICAgICBpZiAocyAmJiBzLmxhc3RGYWlsdXJlICE9PSAwICYmIERhdGUubm93KCkgLSBzLmxhc3RGYWlsdXJlID4gQ09PTERPV05fTVMpIHtcbiAgICAgICAgZGVsZXRlIG1ba2V5XTtcbiAgICAgICAgd3JpdGVNYXAobSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBSZWNvcmQgYSBzdWNjZXNzZnVsIGF1dGggZm9yIHRoaXMgaWRlbnRpZmllciDigJQgY2xlYXJzIGl0cyBmYWlsdXJlIGNvdW50ZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWNvcmRBdXRoU3VjY2VzcyhpZGVudGlmaWVyPzogc3RyaW5nLCBiYXNlVXJsPzogc3RyaW5nKTogdm9pZCB7XG4gIHdpdGhMb2NrKCgpID0+IHtcbiAgICBjb25zdCBtYXAgPSByZWFkTWFwKCk7XG4gICAgZGVsZXRlIG1hcFtrZXlGb3IoaWRlbnRpZmllciwgYmFzZVVybCldO1xuICAgIHdyaXRlTWFwKG1hcCk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFJlY29yZCBhIGZhaWxlZCBhdXRoIGF0dGVtcHQgZm9yIHRoaXMgaWRlbnRpZmllci4gQWZ0ZXIgTUFYX0ZBSUxVUkVTLCBsb2NrcyBvdXRcbiAqIHRoYXQgaWRlbnRpZmllciBmb3IgQ09PTERPV05fTVMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWNvcmRBdXRoRmFpbHVyZShpZGVudGlmaWVyPzogc3RyaW5nLCBiYXNlVXJsPzogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGtleSA9IGtleUZvcihpZGVudGlmaWVyLCBiYXNlVXJsKTtcbiAgLy8gUmVhZC1tb2RpZnktd3JpdGUgdW5kZXIgdGhlIGxvY2s6IGEgY29uY3VycmVudCBDTEkgaW52b2NhdGlvbiBtdXN0IG5vdCByZWFkIHRoZVxuICAvLyBzYW1lIHByZS1pbmNyZW1lbnQgY291bnQgYW5kIG92ZXJ3cml0ZSB0aGlzIG9uZSAod2hpY2ggd291bGQgdW5kZXItY291bnQpLlxuICB3aXRoTG9jaygoKSA9PiB7XG4gICAgY29uc3QgbWFwID0gcmVhZE1hcCgpO1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgY29uc3Qgc3RhdGUgPSB7IC4uLihtYXBba2V5XSA/PyBFTVBUWSkgfTtcbiAgICBzdGF0ZS5mYWlsdXJlcyArPSAxO1xuICAgIHN0YXRlLmxhc3RGYWlsdXJlID0gbm93O1xuICAgIGlmIChzdGF0ZS5mYWlsdXJlcyA+PSBNQVhfRkFJTFVSRVMpIHtcbiAgICAgIHN0YXRlLmxvY2tlZFVudGlsID0gbm93ICsgQ09PTERPV05fTVM7XG4gICAgfVxuICAgIG1hcFtrZXldID0gc3RhdGU7XG4gICAgd3JpdGVNYXAobWFwKTtcbiAgfSk7XG59XG4iXX0=
|