sonamu 0.9.3 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/providers/rtzr/utils.js +2 -2
- package/dist/api/config.d.ts +0 -8
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +1 -1
- package/dist/api/sonamu.d.ts +0 -1
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +2 -41
- package/dist/auth/audit-log/builders.d.ts +216 -0
- package/dist/auth/audit-log/builders.d.ts.map +1 -0
- package/dist/auth/audit-log/builders.js +307 -0
- package/dist/auth/audit-log/events.d.ts +143 -0
- package/dist/auth/audit-log/events.d.ts.map +1 -0
- package/dist/auth/audit-log/events.js +74 -0
- package/dist/auth/audit-log/plugin.d.ts +11 -0
- package/dist/auth/audit-log/plugin.d.ts.map +1 -0
- package/dist/auth/audit-log/plugin.js +427 -0
- package/dist/auth/audit-log-ingestor.d.ts +3 -3
- package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
- package/dist/auth/audit-log-ingestor.js +44 -50
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +4 -4
- package/dist/auth/plugins/entity-definitions/admin.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/admin.js +4 -4
- package/dist/auth/plugins/entity-definitions/audit-log.d.ts +2 -2
- package/dist/auth/plugins/entity-definitions/audit-log.js +3 -3
- package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
- package/dist/auth/plugins/wrappers/sso.d.ts +1 -1
- package/dist/bin/fixture.d.ts.map +1 -1
- package/dist/bin/fixture.js +111 -1
- package/dist/database/_batch_update.d.ts +1 -1
- package/dist/database/_batch_update.js +2 -2
- package/dist/database/upsert-builder.js +4 -4
- package/dist/dict/sonamu-dictionary.js +2 -2
- package/dist/entity/entity-manager.d.ts +2 -2
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +14 -4
- package/dist/index.js +4 -3
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +2 -3
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +2 -9
- package/dist/template/implementations/entry-server.template.js +3 -2
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +2 -1
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +2 -1
- package/dist/template/implementations/queries.template.d.ts.map +1 -1
- package/dist/template/implementations/queries.template.js +3 -1
- package/dist/template/implementations/sd.template.js +3 -2
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +44 -7
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +2 -2
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/data-explorer.js +5 -3
- package/dist/types/types.d.ts +14 -14
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +3 -2
- package/dist/ui-web/assets/index-D4rYm-Xz.css +1 -0
- package/dist/ui-web/assets/{index-DrTfl0Ts.js → index-DzZ7vBk4.js} +47 -47
- package/dist/ui-web/index.html +2 -2
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +4 -4
- package/package.json +4 -5
- package/src/ai/providers/rtzr/utils.ts +1 -1
- package/src/api/config.ts +0 -8
- package/src/api/sonamu.ts +1 -51
- package/src/auth/audit-log/builders.ts +791 -0
- package/src/auth/audit-log/events.ts +149 -0
- package/src/auth/audit-log/plugin.ts +913 -0
- package/src/auth/audit-log-ingestor.ts +3 -4
- package/src/auth/index.ts +2 -0
- package/src/auth/plugins/entity-definitions/admin.ts +3 -3
- package/src/auth/plugins/entity-definitions/audit-log.ts +2 -2
- package/src/bin/fixture.ts +143 -0
- package/src/database/_batch_update.ts +1 -1
- package/src/database/upsert-builder.ts +3 -3
- package/src/dict/sonamu-dictionary.ts +1 -1
- package/src/entity/entity-manager.ts +10 -3
- package/src/migration/code-generation.ts +1 -6
- package/src/shared/app.shared.ts.txt +60 -6
- package/src/shared/web.shared.ts.txt +60 -5
- package/src/syncer/syncer.ts +1 -11
- package/src/template/implementations/entry-server.template.ts +1 -1
- package/src/template/implementations/generated.template.ts +1 -0
- package/src/template/implementations/generated_sso.template.ts +1 -0
- package/src/template/implementations/queries.template.ts +10 -1
- package/src/template/implementations/sd.template.ts +1 -1
- package/src/template/implementations/services.template.ts +62 -6
- package/src/template/zod-converter.ts +2 -1
- package/src/testing/data-explorer.ts +3 -2
- package/src/ui/api.ts +10 -1
- package/src/utils/fs-utils.ts +6 -4
- package/dist/auth/audit-log-proxy-types.d.ts +0 -23
- package/dist/auth/audit-log-proxy-types.d.ts.map +0 -1
- package/dist/auth/audit-log-proxy-types.js +0 -1
- package/dist/ui-web/assets/index-Dr8pRJC_.css +0 -1
- package/src/auth/audit-log-proxy-types.ts +0 -23
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { DB, init_db } from "../../database/db.js";
|
|
2
|
+
import { ROUTES } from "./events.js";
|
|
3
|
+
import { buildAuditEventCatalog } from "./builders.js";
|
|
4
|
+
import { ingestAuditEvent } from "../audit-log-ingestor.js";
|
|
5
|
+
import { getLogger } from "@logtape/logtape";
|
|
6
|
+
import { createAuthMiddleware } from "better-auth/api";
|
|
7
|
+
|
|
8
|
+
//#region src/auth/audit-log/plugin.ts
|
|
9
|
+
init_db();
|
|
10
|
+
const stripQuery = (value) => value.split("?")[0] || value;
|
|
11
|
+
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12
|
+
const routeToRegex = (route) => {
|
|
13
|
+
const pattern = escapeRegex(stripQuery(route)).replace(/\/:([^/]+)/g, "/[^/]+");
|
|
14
|
+
return new RegExp(`${pattern}(?:$|[/?])`);
|
|
15
|
+
};
|
|
16
|
+
const matchesAnyRoute = (routePath, routes) => {
|
|
17
|
+
if (!routePath) return false;
|
|
18
|
+
const cleanPath = stripQuery(routePath);
|
|
19
|
+
return routes.some((route) => routeToRegex(route).test(cleanPath));
|
|
20
|
+
};
|
|
21
|
+
const LOGIN_PATHS = [
|
|
22
|
+
ROUTES.SIGN_IN_SOCIAL_CALLBACK,
|
|
23
|
+
ROUTES.SIGN_IN_OAUTH_CALLBACK,
|
|
24
|
+
ROUTES.SIGN_IN_EMAIL,
|
|
25
|
+
ROUTES.SIGN_IN_SOCIAL,
|
|
26
|
+
ROUTES.SIGN_IN_EMAIL_OTP,
|
|
27
|
+
ROUTES.SIGN_UP_EMAIL
|
|
28
|
+
];
|
|
29
|
+
const getLoginMethod = (ctxPath, paramsId) => {
|
|
30
|
+
if (!ctxPath) return null;
|
|
31
|
+
if (matchesAnyRoute(ctxPath, LOGIN_PATHS)) {
|
|
32
|
+
if (paramsId) return paramsId;
|
|
33
|
+
return ctxPath.split("/").pop() ?? null;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
37
|
+
const getTriggerInfo = (ctxPath, sessionUserId, userId) => {
|
|
38
|
+
const resolved = sessionUserId ?? userId;
|
|
39
|
+
const triggerContext = resolved === userId ? "user" : matchesAnyRoute(ctxPath, [ROUTES.ADMIN_ROUTE]) ? "admin" : matchesAnyRoute(ctxPath, [ROUTES.DASH_ROUTE]) ? "dashboard" : resolved === "unknown" ? "user" : "unknown";
|
|
40
|
+
return {
|
|
41
|
+
triggeredBy: resolved,
|
|
42
|
+
triggerContext
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const getOrganizationTriggerInfo = (user) => ({
|
|
46
|
+
triggeredBy: user?.id ?? "unknown",
|
|
47
|
+
triggerContext: "organization"
|
|
48
|
+
});
|
|
49
|
+
const narrowRequestCtx = (raw) => {
|
|
50
|
+
if (!raw || typeof raw !== "object") return null;
|
|
51
|
+
const candidate = raw;
|
|
52
|
+
if (!candidate.context || typeof candidate.context !== "object") return null;
|
|
53
|
+
return raw;
|
|
54
|
+
};
|
|
55
|
+
const fetchUserBy = async (ctx, field, value) => {
|
|
56
|
+
if (!value) return null;
|
|
57
|
+
const adapter = ctx.context.adapter;
|
|
58
|
+
if (!adapter) return null;
|
|
59
|
+
try {
|
|
60
|
+
const row = await adapter.findOne({
|
|
61
|
+
model: "user",
|
|
62
|
+
select: [
|
|
63
|
+
"id",
|
|
64
|
+
"name",
|
|
65
|
+
"email"
|
|
66
|
+
],
|
|
67
|
+
where: [{
|
|
68
|
+
field,
|
|
69
|
+
value
|
|
70
|
+
}]
|
|
71
|
+
});
|
|
72
|
+
if (!row) return null;
|
|
73
|
+
return {
|
|
74
|
+
id: String(row.id),
|
|
75
|
+
name: typeof row.name === "string" ? row.name : undefined,
|
|
76
|
+
email: typeof row.email === "string" ? row.email : undefined
|
|
77
|
+
};
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
|
|
83
|
+
const IP_HEADER_ORDER = [
|
|
84
|
+
"cf-connecting-ip",
|
|
85
|
+
"x-forwarded-for",
|
|
86
|
+
"x-real-ip",
|
|
87
|
+
"x-vercel-forwarded-for"
|
|
88
|
+
];
|
|
89
|
+
const readHeader = (headers, key) => {
|
|
90
|
+
if (!headers) return null;
|
|
91
|
+
if (headers instanceof Headers) {
|
|
92
|
+
return headers.get(key);
|
|
93
|
+
}
|
|
94
|
+
if (typeof headers === "object") {
|
|
95
|
+
const map = headers;
|
|
96
|
+
const v = map[key] ?? map[key.toLowerCase()];
|
|
97
|
+
if (typeof v === "string") return v;
|
|
98
|
+
if (Array.isArray(v) && typeof v[0] === "string") return v[0];
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
};
|
|
102
|
+
const extractLocationFromHeaders = (headers) => {
|
|
103
|
+
let ipAddress = null;
|
|
104
|
+
for (const key of IP_HEADER_ORDER) {
|
|
105
|
+
const raw = readHeader(headers, key);
|
|
106
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
107
|
+
const first = raw.split(",")[0]?.trim();
|
|
108
|
+
if (first) {
|
|
109
|
+
ipAddress = first;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const countryCode = readHeader(headers, "cf-ipcountry");
|
|
115
|
+
const city = readHeader(headers, "cf-ipcity");
|
|
116
|
+
return {
|
|
117
|
+
ipAddress: ipAddress ?? undefined,
|
|
118
|
+
city: city ?? undefined,
|
|
119
|
+
country: undefined,
|
|
120
|
+
countryCode: countryCode ?? undefined
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
const wrapOrgHook = (hooks, name, handler) => {
|
|
124
|
+
const prev = hooks[name];
|
|
125
|
+
hooks[name] = async (...args) => {
|
|
126
|
+
await handler(args[0]);
|
|
127
|
+
if (prev) return prev(...args);
|
|
128
|
+
return undefined;
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Better Auth databaseHooks/organizationHooks/middleware에서 수집한
|
|
133
|
+
* 이벤트를 `DB.getDB("w")`로 얻은 knex에 `ingestAuditEvent`로 적재한다.
|
|
134
|
+
*
|
|
135
|
+
* - dash(@better-auth/infra)의 audit-event 수집 훅 구조를 참고해 Sonamu 내부 적재 경로로 포팅한다.
|
|
136
|
+
* - dash의 infra 연결/API endpoint 제공 범위는 포함하지 않고, audit-event emit/ingest 경로만 유지한다.
|
|
137
|
+
* - security 4종은 R1 결정에 따라 scope out (builders.ts의 TODO 주석 참조).
|
|
138
|
+
*/
|
|
139
|
+
function sonamuAuditLog() {
|
|
140
|
+
const logger = getLogger(["sonamu", "audit-log"]);
|
|
141
|
+
const catalog = buildAuditEventCatalog();
|
|
142
|
+
const processedBulkOperationContexts = new WeakSet();
|
|
143
|
+
const emit = async (event) => {
|
|
144
|
+
try {
|
|
145
|
+
await ingestAuditEvent(DB.getDB("w"), event);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
logger.error("audit event ingest failed: {error}", { error: err });
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const triggerFor = (ctx, subjectUserId) => getTriggerInfo(ctx.path, ctx.context.session?.session?.userId ?? null, subjectUserId);
|
|
151
|
+
const locationFor = (ctx) => ctx.context.location ?? undefined;
|
|
152
|
+
return {
|
|
153
|
+
id: "sonamu-audit-log",
|
|
154
|
+
init(pluginCtx) {
|
|
155
|
+
installOrganizationHooks(pluginCtx, catalog, emit, logger);
|
|
156
|
+
return { options: { databaseHooks: {
|
|
157
|
+
user: {
|
|
158
|
+
create: { after: async (rawUser, rawCtx) => {
|
|
159
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
160
|
+
if (!ctx) return;
|
|
161
|
+
const user = rawUser;
|
|
162
|
+
await emit(catalog.user.trackUserSignedUp(user, triggerFor(ctx, user.id), locationFor(ctx)));
|
|
163
|
+
} },
|
|
164
|
+
update: { after: async (rawUser, rawCtx) => {
|
|
165
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
166
|
+
if (!ctx) return;
|
|
167
|
+
const user = rawUser;
|
|
168
|
+
const path = ctx.path;
|
|
169
|
+
const trigger = triggerFor(ctx, user.id);
|
|
170
|
+
const location = locationFor(ctx);
|
|
171
|
+
if (matchesAnyRoute(path, [ROUTES.UPDATE_USER, ROUTES.DASH_UPDATE_USER])) {
|
|
172
|
+
const updatedFields = Object.keys(ctx.body ?? {});
|
|
173
|
+
const isOnlyImageUpdate = updatedFields.length === 1 && updatedFields[0] === "image";
|
|
174
|
+
const isOnlyEmailVerifiedUpdate = updatedFields.length === 1 && updatedFields[0] === "emailVerified";
|
|
175
|
+
const hasEmailVerifiedUpdate = updatedFields.includes("emailVerified");
|
|
176
|
+
if (isOnlyEmailVerifiedUpdate && user.emailVerified) {
|
|
177
|
+
await emit(catalog.user.trackUserEmailVerified(user, trigger, location));
|
|
178
|
+
} else if (isOnlyImageUpdate && user.image) {
|
|
179
|
+
await emit(catalog.user.trackUserProfileImageUpdated(user, trigger, location));
|
|
180
|
+
} else if (!isOnlyImageUpdate && !isOnlyEmailVerifiedUpdate) {
|
|
181
|
+
await emit(catalog.user.trackUserProfileUpdated(user, updatedFields, trigger, location));
|
|
182
|
+
if (hasEmailVerifiedUpdate && user.emailVerified) {
|
|
183
|
+
await emit(catalog.user.trackUserEmailVerified(user, trigger, location));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
} else if (matchesAnyRoute(path, [ROUTES.CHANGE_EMAIL])) {
|
|
187
|
+
const updatedFields = Object.keys(ctx.body ?? {});
|
|
188
|
+
await emit(catalog.user.trackUserProfileUpdated(user, updatedFields, trigger, location));
|
|
189
|
+
}
|
|
190
|
+
if (matchesAnyRoute(path, [ROUTES.VERIFY_EMAIL]) && user.emailVerified) {
|
|
191
|
+
await emit(catalog.user.trackUserEmailVerified(user, trigger, location));
|
|
192
|
+
}
|
|
193
|
+
if (matchesAnyRoute(path, [ROUTES.ADMIN_BAN_USER]) && "banned" in user && user.banned) {
|
|
194
|
+
await emit(catalog.user.trackUserBanned(user, trigger, location));
|
|
195
|
+
}
|
|
196
|
+
if (matchesAnyRoute(path, [ROUTES.ADMIN_UNBAN_USER]) && "banned" in user && !user.banned) {
|
|
197
|
+
await emit(catalog.user.trackUserUnBanned(user, trigger, location));
|
|
198
|
+
}
|
|
199
|
+
} },
|
|
200
|
+
delete: { after: async (rawUser, rawCtx) => {
|
|
201
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
202
|
+
if (!ctx) return;
|
|
203
|
+
const user = rawUser;
|
|
204
|
+
await emit(catalog.user.trackUserDeleted(user, triggerFor(ctx, user.id), locationFor(ctx)));
|
|
205
|
+
} }
|
|
206
|
+
},
|
|
207
|
+
session: {
|
|
208
|
+
create: {
|
|
209
|
+
before: async (rawSession, rawCtx) => {
|
|
210
|
+
void rawSession;
|
|
211
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
212
|
+
if (!ctx) return undefined;
|
|
213
|
+
return { data: { loginMethod: getLoginMethod(ctx.path, ctx.params?.id) } };
|
|
214
|
+
},
|
|
215
|
+
after: async (rawSession, rawCtx) => {
|
|
216
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
217
|
+
if (!ctx) return;
|
|
218
|
+
const session = rawSession;
|
|
219
|
+
if (!session.userId) return;
|
|
220
|
+
const location = locationFor(ctx);
|
|
221
|
+
const loginMethod = getLoginMethod(ctx.path, ctx.params?.id) ?? undefined;
|
|
222
|
+
const enrichedSession = {
|
|
223
|
+
...session,
|
|
224
|
+
loginMethod: loginMethod ?? session.loginMethod ?? null
|
|
225
|
+
};
|
|
226
|
+
const user = await fetchUserBy(ctx, "id", session.userId);
|
|
227
|
+
let trigger;
|
|
228
|
+
if (matchesAnyRoute(ctx.path, [
|
|
229
|
+
ROUTES.SIGN_IN,
|
|
230
|
+
ROUTES.SIGN_UP,
|
|
231
|
+
ROUTES.SIGN_IN_SOCIAL_CALLBACK,
|
|
232
|
+
ROUTES.SIGN_IN_OAUTH_CALLBACK
|
|
233
|
+
])) {
|
|
234
|
+
trigger = getTriggerInfo(ctx.path, session.userId, session.userId);
|
|
235
|
+
await emit(catalog.session.trackUserSignedIn(enrichedSession, user, trigger, location));
|
|
236
|
+
} else {
|
|
237
|
+
trigger = triggerFor(ctx, session.userId);
|
|
238
|
+
}
|
|
239
|
+
await emit(catalog.session.trackSessionCreated(enrichedSession, user, trigger, location));
|
|
240
|
+
if (isNonEmptyString(session.impersonatedBy)) {
|
|
241
|
+
const impersonator = await fetchUserBy(ctx, "id", session.impersonatedBy);
|
|
242
|
+
await emit(catalog.session.trackUserImpersonated(enrichedSession, user, impersonator, {
|
|
243
|
+
triggeredBy: session.impersonatedBy,
|
|
244
|
+
triggerContext: trigger.triggerContext
|
|
245
|
+
}, location));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
delete: { after: async (rawSession, rawCtx) => {
|
|
250
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
251
|
+
if (!ctx) return;
|
|
252
|
+
const session = rawSession;
|
|
253
|
+
const location = locationFor(ctx);
|
|
254
|
+
const enrichedSession = { ...session };
|
|
255
|
+
const user = await fetchUserBy(ctx, "id", session.userId);
|
|
256
|
+
const trigger = triggerFor(ctx, session.userId);
|
|
257
|
+
if (matchesAnyRoute(ctx.path, [
|
|
258
|
+
ROUTES.REVOKE_ALL_SESSIONS,
|
|
259
|
+
ROUTES.ADMIN_REVOKE_USER_SESSIONS,
|
|
260
|
+
ROUTES.DASH_REVOKE_SESSIONS_ALL,
|
|
261
|
+
ROUTES.DASH_BAN_USER
|
|
262
|
+
])) {
|
|
263
|
+
if (!processedBulkOperationContexts.has(ctx)) {
|
|
264
|
+
await emit(catalog.session.trackSessionRevokedAll(enrichedSession, user, trigger));
|
|
265
|
+
processedBulkOperationContexts.add(ctx);
|
|
266
|
+
}
|
|
267
|
+
} else if (matchesAnyRoute(ctx.path, [ROUTES.SIGN_OUT])) {
|
|
268
|
+
await emit(catalog.session.trackUserSignedOut(enrichedSession, user, trigger, location));
|
|
269
|
+
} else {
|
|
270
|
+
await emit(catalog.session.trackSessionRevoked(enrichedSession, user, trigger, location));
|
|
271
|
+
}
|
|
272
|
+
if (isNonEmptyString(session.impersonatedBy)) {
|
|
273
|
+
const impersonator = await fetchUserBy(ctx, "id", session.impersonatedBy);
|
|
274
|
+
await emit(catalog.session.trackUserImpersonationStop(enrichedSession, user, impersonator, trigger, location));
|
|
275
|
+
}
|
|
276
|
+
} }
|
|
277
|
+
},
|
|
278
|
+
account: {
|
|
279
|
+
create: { after: async (rawAccount, rawCtx) => {
|
|
280
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
281
|
+
if (!ctx) return;
|
|
282
|
+
const account = rawAccount;
|
|
283
|
+
if (!account.userId) return;
|
|
284
|
+
const user = await fetchUserBy(ctx, "id", account.userId);
|
|
285
|
+
await emit(catalog.account.trackAccountLinking(account, user, triggerFor(ctx, account.userId), locationFor(ctx)));
|
|
286
|
+
} },
|
|
287
|
+
update: { after: async (rawAccount, rawCtx) => {
|
|
288
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
289
|
+
if (!ctx) return;
|
|
290
|
+
const account = rawAccount;
|
|
291
|
+
if (!account.userId) return;
|
|
292
|
+
if (!matchesAnyRoute(ctx.path, [
|
|
293
|
+
ROUTES.CHANGE_PASSWORD,
|
|
294
|
+
ROUTES.SET_PASSWORD,
|
|
295
|
+
ROUTES.RESET_PASSWORD,
|
|
296
|
+
ROUTES.ADMIN_SET_PASSWORD
|
|
297
|
+
])) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const user = await fetchUserBy(ctx, "id", account.userId);
|
|
301
|
+
await emit(catalog.account.trackAccountPasswordChange(account, user, triggerFor(ctx, account.userId), locationFor(ctx)));
|
|
302
|
+
} },
|
|
303
|
+
delete: { after: async (rawAccount, rawCtx) => {
|
|
304
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
305
|
+
if (!ctx) return;
|
|
306
|
+
const account = rawAccount;
|
|
307
|
+
if (!account.userId) return;
|
|
308
|
+
const user = await fetchUserBy(ctx, "id", account.userId);
|
|
309
|
+
await emit(catalog.account.trackAccountUnlink(account, user, triggerFor(ctx, account.userId), locationFor(ctx)));
|
|
310
|
+
} }
|
|
311
|
+
},
|
|
312
|
+
verification: {
|
|
313
|
+
create: { after: async (rawVerification, rawCtx) => {
|
|
314
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
315
|
+
if (!ctx) return;
|
|
316
|
+
if (!matchesAnyRoute(ctx.path, [ROUTES.REQUEST_PASSWORD_RESET])) return;
|
|
317
|
+
const verification = rawVerification;
|
|
318
|
+
const sessionUserId = ctx.context.session?.user?.id ?? "unknown";
|
|
319
|
+
const trigger = getTriggerInfo(ctx.path, sessionUserId, sessionUserId);
|
|
320
|
+
const user = await fetchUserBy(ctx, "id", verification.value);
|
|
321
|
+
await emit(catalog.verification.trackPasswordResetRequest(verification, user, trigger, locationFor(ctx)));
|
|
322
|
+
} },
|
|
323
|
+
delete: { after: async (rawVerification, rawCtx) => {
|
|
324
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
325
|
+
if (!ctx) return;
|
|
326
|
+
if (!matchesAnyRoute(ctx.path, [ROUTES.RESET_PASSWORD])) return;
|
|
327
|
+
const verification = rawVerification;
|
|
328
|
+
const sessionUserId = ctx.context.session?.user?.id ?? "unknown";
|
|
329
|
+
const trigger = getTriggerInfo(ctx.path, sessionUserId, sessionUserId);
|
|
330
|
+
const user = await fetchUserBy(ctx, "id", verification.value);
|
|
331
|
+
await emit(catalog.verification.trackPasswordResetRequestCompletion(verification, user, trigger, locationFor(ctx)));
|
|
332
|
+
} }
|
|
333
|
+
}
|
|
334
|
+
} } };
|
|
335
|
+
},
|
|
336
|
+
hooks: {
|
|
337
|
+
before: [{
|
|
338
|
+
matcher: () => true,
|
|
339
|
+
handler: createAuthMiddleware(async (rawCtx) => {
|
|
340
|
+
const ctx = rawCtx;
|
|
341
|
+
if (!ctx.context) return;
|
|
342
|
+
const headers = ctx.headers ?? ctx.request?.headers;
|
|
343
|
+
ctx.context.location = extractLocationFromHeaders(headers);
|
|
344
|
+
})
|
|
345
|
+
}],
|
|
346
|
+
after: [{
|
|
347
|
+
matcher: (ctx) => {
|
|
348
|
+
const c = ctx;
|
|
349
|
+
if (c.request?.method !== "GET") return true;
|
|
350
|
+
if (!c.request.url) return false;
|
|
351
|
+
try {
|
|
352
|
+
const p = new URL(c.request.url).pathname;
|
|
353
|
+
return matchesAnyRoute(p, [ROUTES.SIGN_IN_SOCIAL_CALLBACK, ROUTES.SIGN_IN_OAUTH_CALLBACK]);
|
|
354
|
+
} catch {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
handler: createAuthMiddleware(async (rawCtx) => {
|
|
359
|
+
const ctx = narrowRequestCtx(rawCtx);
|
|
360
|
+
if (!ctx) return;
|
|
361
|
+
const sessionUser = ctx.context.session?.user;
|
|
362
|
+
const sessionUserId = sessionUser?.id ?? "unknown";
|
|
363
|
+
const trigger = getTriggerInfo(ctx.path, sessionUserId, sessionUserId);
|
|
364
|
+
const location = locationFor(ctx);
|
|
365
|
+
const returned = ctx.context.returned;
|
|
366
|
+
const isErrored = returned instanceof Error;
|
|
367
|
+
if (matchesAnyRoute(ctx.path, [ROUTES.SEND_VERIFICATION_EMAIL]) && ctx.context.session && !isErrored) {
|
|
368
|
+
const sessionEntity = ctx.context.session.session;
|
|
369
|
+
const user = ctx.context.session.user;
|
|
370
|
+
if (sessionEntity && user) {
|
|
371
|
+
await emit(catalog.session.trackEmailVerificationSent(sessionEntity, user, trigger));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
const body = ctx.body ?? null;
|
|
375
|
+
if (matchesAnyRoute(ctx.path, [ROUTES.SIGN_IN_EMAIL, ROUTES.SIGN_IN_EMAIL_OTP]) && isErrored && body?.email) {
|
|
376
|
+
const user = await fetchUserBy(ctx, "email", body.email);
|
|
377
|
+
await emit(catalog.session.trackEmailSignInAttempt({
|
|
378
|
+
email: body.email,
|
|
379
|
+
loginMethod: getLoginMethod(ctx.path, ctx.params?.id)
|
|
380
|
+
}, user, trigger, location));
|
|
381
|
+
}
|
|
382
|
+
if (matchesAnyRoute(ctx.path, [ROUTES.SIGN_IN_SOCIAL]) && isErrored && body?.provider && body?.idToken) {
|
|
383
|
+
await emit(catalog.session.trackSocialSignInAttempt({ loginMethod: getLoginMethod(ctx.path, ctx.params?.id) }, null, trigger, location));
|
|
384
|
+
}
|
|
385
|
+
if (matchesAnyRoute(ctx.path, [ROUTES.SIGN_IN_SOCIAL_CALLBACK]) && isErrored) {
|
|
386
|
+
await emit(catalog.session.trackSocialSignInRedirectionAttempt({ loginMethod: getLoginMethod(ctx.path, ctx.params?.id) }, null, trigger, location));
|
|
387
|
+
}
|
|
388
|
+
})
|
|
389
|
+
}]
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function installOrganizationHooks(pluginCtx, catalog, emit, logger) {
|
|
394
|
+
const getPlugin = pluginCtx?.getPlugin;
|
|
395
|
+
const organizationPlugin = typeof getPlugin === "function" ? getPlugin.call(pluginCtx, "organization") : null;
|
|
396
|
+
if (!organizationPlugin || typeof organizationPlugin !== "object") {
|
|
397
|
+
logger.debug("organization plugin not active; skipping instrumentation");
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const orgPlugin = organizationPlugin;
|
|
401
|
+
orgPlugin.options = orgPlugin.options ?? {};
|
|
402
|
+
const hooks = orgPlugin.options.organizationHooks = orgPlugin.options.organizationHooks ?? {};
|
|
403
|
+
wrapOrgHook(hooks, "afterCreateOrganization", async (p) => emit(catalog.organization.trackOrganizationCreated(p.organization, getOrganizationTriggerInfo(p.user))));
|
|
404
|
+
wrapOrgHook(hooks, "afterUpdateOrganization", async (p) => {
|
|
405
|
+
if (!p.organization) return;
|
|
406
|
+
await emit(catalog.organization.trackOrganizationUpdated(p.organization, getOrganizationTriggerInfo(p.user)));
|
|
407
|
+
});
|
|
408
|
+
wrapOrgHook(hooks, "afterAddMember", async (p) => emit(catalog.member.trackOrganizationMemberAdded(p.organization, p.member, p.user, getOrganizationTriggerInfo(p.user))));
|
|
409
|
+
wrapOrgHook(hooks, "afterRemoveMember", async (p) => emit(catalog.member.trackOrganizationMemberRemoved(p.organization, p.member, p.user, getOrganizationTriggerInfo(p.user))));
|
|
410
|
+
wrapOrgHook(hooks, "afterUpdateMemberRole", async (p) => emit(catalog.member.trackOrganizationMemberRoleUpdated(p.organization, p.member, p.user, p.previousRole, getOrganizationTriggerInfo(p.user))));
|
|
411
|
+
wrapOrgHook(hooks, "afterCreateInvitation", async (p) => emit(catalog.invitation.trackOrganizationMemberInvited(p.organization, p.invitation, p.inviter, getOrganizationTriggerInfo(p.inviter))));
|
|
412
|
+
wrapOrgHook(hooks, "afterAcceptInvitation", async (p) => emit(catalog.invitation.trackOrganizationMemberInviteAccepted(p.organization, p.invitation, p.member, p.user, getOrganizationTriggerInfo(p.user))));
|
|
413
|
+
wrapOrgHook(hooks, "afterRejectInvitation", async (p) => emit(catalog.invitation.trackOrganizationMemberInviteRejected(p.organization, p.invitation, p.user, getOrganizationTriggerInfo(p.user))));
|
|
414
|
+
wrapOrgHook(hooks, "afterCancelInvitation", async (p) => emit(catalog.invitation.trackOrganizationMemberInviteCanceled(p.organization, p.invitation, p.cancelledBy, getOrganizationTriggerInfo(p.cancelledBy))));
|
|
415
|
+
wrapOrgHook(hooks, "afterCreateTeam", async (p) => emit(catalog.team.trackOrganizationTeamCreated(p.organization, p.team, getOrganizationTriggerInfo(p.user))));
|
|
416
|
+
wrapOrgHook(hooks, "afterUpdateTeam", async (p) => {
|
|
417
|
+
if (!p.team) return;
|
|
418
|
+
await emit(catalog.team.trackOrganizationTeamUpdated(p.organization, p.team, getOrganizationTriggerInfo(p.user)));
|
|
419
|
+
});
|
|
420
|
+
wrapOrgHook(hooks, "afterDeleteTeam", async (p) => emit(catalog.team.trackOrganizationTeamDeleted(p.organization, p.team, getOrganizationTriggerInfo(p.user))));
|
|
421
|
+
wrapOrgHook(hooks, "afterAddTeamMember", async (p) => emit(catalog.team.trackOrganizationTeamMemberAdded(p.organization, p.team, p.user, p.teamMember, getOrganizationTriggerInfo(p.user))));
|
|
422
|
+
wrapOrgHook(hooks, "afterRemoveTeamMember", async (p) => emit(catalog.team.trackOrganizationTeamMemberRemoved(p.organization, p.team, p.user, p.teamMember, getOrganizationTriggerInfo(p.user))));
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
//#endregion
|
|
426
|
+
export { sonamuAuditLog };
|
|
427
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwibmFtZXMiOlsiaXBBZGRyZXNzOiBzdHJpbmcgfCBudWxsIiwiZW5yaWNoZWRTZXNzaW9uOiBTZXNzaW9uU25hcHNob3QiLCJ0cmlnZ2VyOiBCdWlsZGVyVHJpZ2dlciJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hdXRoL2F1ZGl0LWxvZy9wbHVnaW4udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZ2V0TG9nZ2VyIH0gZnJvbSBcIkBsb2d0YXBlL2xvZ3RhcGVcIjtcbmltcG9ydCB7IHR5cGUgQmV0dGVyQXV0aFBsdWdpbiB9IGZyb20gXCJiZXR0ZXItYXV0aFwiO1xuaW1wb3J0IHsgY3JlYXRlQXV0aE1pZGRsZXdhcmUgfSBmcm9tIFwiYmV0dGVyLWF1dGgvYXBpXCI7XG5cbmltcG9ydCB7IERCIH0gZnJvbSBcIi4uLy4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyBpbmdlc3RBdWRpdEV2ZW50IH0gZnJvbSBcIi4uL2F1ZGl0LWxvZy1pbmdlc3RvclwiO1xuaW1wb3J0IHsgYnVpbGRBdWRpdEV2ZW50Q2F0YWxvZyB9IGZyb20gXCIuL2J1aWxkZXJzXCI7XG5pbXBvcnQge1xuICB0eXBlIEFjY291bnRTbmFwc2hvdCxcbiAgdHlwZSBBdWRpdExvZ0V2ZW50LFxuICB0eXBlIEJ1aWxkZXJMb2NhdGlvbixcbiAgdHlwZSBCdWlsZGVyVHJpZ2dlcixcbiAgdHlwZSBJbnZpdGF0aW9uU25hcHNob3QsXG4gIHR5cGUgTWVtYmVyU25hcHNob3QsXG4gIHR5cGUgT3JnYW5pemF0aW9uU25hcHNob3QsXG4gIFJPVVRFUyxcbiAgdHlwZSBTZXNzaW9uU25hcHNob3QsXG4gIHR5cGUgVGVhbVNuYXBzaG90LFxuICB0eXBlIFVzZXJQcm9maWxlTGl0ZSxcbiAgdHlwZSBVc2VyU25hcHNob3QsXG4gIHR5cGUgVmVyaWZpY2F0aW9uU25hcHNob3QsXG59IGZyb20gXCIuL2V2ZW50c1wiO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyDrnbzsmrDtjIUv7Yq466as6rGwIOycoO2LuFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuY29uc3Qgc3RyaXBRdWVyeSA9ICh2YWx1ZTogc3RyaW5nKTogc3RyaW5nID0+IHZhbHVlLnNwbGl0KFwiP1wiKVswXSB8fCB2YWx1ZTtcbmNvbnN0IGVzY2FwZVJlZ2V4ID0gKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcgPT4gdmFsdWUucmVwbGFjZSgvWy4qKz9eJHt9KCl8W1xcXVxcXFxdL2csIFwiXFxcXCQmXCIpO1xuY29uc3Qgcm91dGVUb1JlZ2V4ID0gKHJvdXRlOiBzdHJpbmcpOiBSZWdFeHAgPT4ge1xuICBjb25zdCBwYXR0ZXJuID0gZXNjYXBlUmVnZXgoc3RyaXBRdWVyeShyb3V0ZSkpLnJlcGxhY2UoL1xcLzooW14vXSspL2csIFwiL1teL10rXCIpO1xuICByZXR1cm4gbmV3IFJlZ0V4cChgJHtwYXR0ZXJufSg/OiR8Wy8/XSlgKTtcbn07XG5jb25zdCBtYXRjaGVzQW55Um91dGUgPSAocm91dGVQYXRoOiBzdHJpbmcgfCB1bmRlZmluZWQsIHJvdXRlczogcmVhZG9ubHkgc3RyaW5nW10pOiBib29sZWFuID0+IHtcbiAgaWYgKCFyb3V0ZVBhdGgpIHJldHVybiBmYWxzZTtcbiAgY29uc3QgY2xlYW5QYXRoID0gc3RyaXBRdWVyeShyb3V0ZVBhdGgpO1xuICByZXR1cm4gcm91dGVzLnNvbWUoKHJvdXRlKSA9PiByb3V0ZVRvUmVnZXgocm91dGUpLnRlc3QoY2xlYW5QYXRoKSk7XG59O1xuXG5jb25zdCBMT0dJTl9QQVRIUyA9IFtcbiAgUk9VVEVTLlNJR05fSU5fU09DSUFMX0NBTExCQUNLLFxuICBST1VURVMuU0lHTl9JTl9PQVVUSF9DQUxMQkFDSyxcbiAgUk9VVEVTLlNJR05fSU5fRU1BSUwsXG4gIFJPVVRFUy5TSUdOX0lOX1NPQ0lBTCxcbiAgUk9VVEVTLlNJR05fSU5fRU1BSUxfT1RQLFxuICBST1VURVMuU0lHTl9VUF9FTUFJTCxcbl0gYXMgY29uc3Q7XG5cbi8vIGRhc2ggMzE5LTMyMyDrr7jrn6w6IO2YhOyerCDsmpTssq0gcGF0aOyXkOyEnCDroZzqt7jsnbgg67Cp7Iud7J2EIOy2lOy2nO2VnOuLpC5cbmNvbnN0IGdldExvZ2luTWV0aG9kID0gKGN0eFBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZCwgcGFyYW1zSWQ/OiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsID0+IHtcbiAgaWYgKCFjdHhQYXRoKSByZXR1cm4gbnVsbDtcbiAgaWYgKG1hdGNoZXNBbnlSb3V0ZShjdHhQYXRoLCBMT0dJTl9QQVRIUykpIHtcbiAgICBpZiAocGFyYW1zSWQpIHJldHVybiBwYXJhbXNJZDtcbiAgICByZXR1cm4gY3R4UGF0aC5zcGxpdChcIi9cIikucG9wKCkgPz8gbnVsbDtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn07XG5cbi8vIGRhc2ggNzk3LTgwMyDrr7jrn6w6IOyEuOyFmC/smpTssq3sl5DshJwg7Yq466as6rGwIOyjvOyytOyZgCDsu6jthY3siqTtirjrpbwg64+E7Lac7ZWc64ukLlxuY29uc3QgZ2V0VHJpZ2dlckluZm8gPSAoXG4gIGN0eFBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgc2Vzc2lvblVzZXJJZDogc3RyaW5nIHwgbnVsbCxcbiAgdXNlcklkOiBzdHJpbmcsXG4pOiBCdWlsZGVyVHJpZ2dlciA9PiB7XG4gIGNvbnN0IHJlc29sdmVkID0gc2Vzc2lvblVzZXJJZCA/PyB1c2VySWQ7XG4gIGNvbnN0IHRyaWdnZXJDb250ZXh0ID1cbiAgICByZXNvbHZlZCA9PT0gdXNlcklkXG4gICAgICA/IFwidXNlclwiXG4gICAgICA6IG1hdGNoZXNBbnlSb3V0ZShjdHhQYXRoLCBbUk9VVEVTLkFETUlOX1JPVVRFXSlcbiAgICAgICAgPyBcImFkbWluXCJcbiAgICAgICAgOiBtYXRjaGVzQW55Um91dGUoY3R4UGF0aCwgW1JPVVRFUy5EQVNIX1JPVVRFXSlcbiAgICAgICAgICA/IFwiZGFzaGJvYXJkXCJcbiAgICAgICAgICA6IHJlc29sdmVkID09PSBcInVua25vd25cIlxuICAgICAgICAgICAgPyBcInVzZXJcIlxuICAgICAgICAgICAgOiBcInVua25vd25cIjtcbiAgcmV0dXJuIHsgdHJpZ2dlcmVkQnk6IHJlc29sdmVkLCB0cmlnZ2VyQ29udGV4dCB9O1xufTtcblxuLy8gZGFzaCA4MDktODE0IOuvuOufrDogb3JnYW5pemF0aW9uIGhvb2vsnYAg7J247KadIOy7qO2FjeyKpO2KuCDsl4bsnbTrj4Qg7Zi47Lac65CY66+A66GcXG4vLyDso7zslrTsp4QgdXNlciDqsJ3ssrTroZzrtoDthLAg7Yq466as6rGwIOygleuztOulvCDtlanshLHtlZzri6QuXG5jb25zdCBnZXRPcmdhbml6YXRpb25UcmlnZ2VySW5mbyA9ICh1c2VyOiB7IGlkPzogc3RyaW5nIH0gfCBudWxsIHwgdW5kZWZpbmVkKTogQnVpbGRlclRyaWdnZXIgPT4gKHtcbiAgdHJpZ2dlcmVkQnk6IHVzZXI/LmlkID8/IFwidW5rbm93blwiLFxuICB0cmlnZ2VyQ29udGV4dDogXCJvcmdhbml6YXRpb25cIixcbn0pO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBiZXR0ZXItYXV0aCBjdHgg7YOA7J6FIGhlbHBlcnMgKOuCtOu2gCBzaGFwZeydgCDrn7Dtg4DsnoQg6rWs7KGw66W8IOq4sOykgOycvOuhnCDsooHtmIAg7IKs7Jqp7ZWc64ukKVxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxudHlwZSBCZXR0ZXJBdXRoUmVxdWVzdEN0eCA9IHtcbiAgcGF0aD86IHN0cmluZztcbiAgYm9keT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgbnVsbCB8IHVuZGVmaW5lZDtcbiAgcGFyYW1zPzogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPiB8IG51bGwgfCB1bmRlZmluZWQ7XG4gIGNvbnRleHQ6IHtcbiAgICBzZXNzaW9uPzoge1xuICAgICAgc2Vzc2lvbj86IHsgdXNlcklkPzogc3RyaW5nIH07XG4gICAgICB1c2VyPzogeyBpZD86IHN0cmluZyB9O1xuICAgIH0gfCBudWxsO1xuICAgIGxvY2F0aW9uPzogQnVpbGRlckxvY2F0aW9uIHwgbnVsbDtcbiAgICBhZGFwdGVyPzoge1xuICAgICAgZmluZE9uZTogKGFyZ3M6IHtcbiAgICAgICAgbW9kZWw6IHN0cmluZztcbiAgICAgICAgc2VsZWN0Pzogc3RyaW5nW107XG4gICAgICAgIHdoZXJlOiB7IGZpZWxkOiBzdHJpbmc7IHZhbHVlOiB1bmtub3duIH1bXTtcbiAgICAgIH0pID0+IFByb21pc2U8UmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsPjtcbiAgICB9O1xuICAgIHJldHVybmVkPzogdW5rbm93bjtcbiAgfTtcbn07XG5cbi8vIGRhdGFiYXNlSG9va3MgYWZ0ZXIg7L2c67Cx7J2YIGN0eOuKlCDshKDtg53soIHsnbTrqbAgc2hhcGXsnYQg65+w7YOA7J6E7JeQ7IScIOyige2ejOuLpC5cbmNvbnN0IG5hcnJvd1JlcXVlc3RDdHggPSAocmF3OiB1bmtub3duKTogQmV0dGVyQXV0aFJlcXVlc3RDdHggfCBudWxsID0+IHtcbiAgaWYgKCFyYXcgfHwgdHlwZW9mIHJhdyAhPT0gXCJvYmplY3RcIikgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGNhbmRpZGF0ZSA9IHJhdyBhcyB7IGNvbnRleHQ/OiB1bmtub3duIH07XG4gIGlmICghY2FuZGlkYXRlLmNvbnRleHQgfHwgdHlwZW9mIGNhbmRpZGF0ZS5jb250ZXh0ICE9PSBcIm9iamVjdFwiKSByZXR1cm4gbnVsbDtcbiAgcmV0dXJuIHJhdyBhcyBCZXR0ZXJBdXRoUmVxdWVzdEN0eDtcbn07XG5cbi8vIGFkYXB0ZXIuZmluZE9uZSDtmLjstpwg7Iuk7YyoIOyLnCBudWxs7J2EIOuwmO2ZmO2VnOuLpC4gZGFzaCDtl6ztjbzsmYAg64+Z7J28IOygleyxhS5cbmNvbnN0IGZldGNoVXNlckJ5ID0gYXN5bmMgKFxuICBjdHg6IEJldHRlckF1dGhSZXF1ZXN0Q3R4LFxuICBmaWVsZDogXCJpZFwiIHwgXCJlbWFpbFwiLFxuICB2YWx1ZTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCxcbik6IFByb21pc2U8VXNlclByb2ZpbGVMaXRlPiA9PiB7XG4gIGlmICghdmFsdWUpIHJldHVybiBudWxsO1xuICBjb25zdCBhZGFwdGVyID0gY3R4LmNvbnRleHQuYWRhcHRlcjtcbiAgaWYgKCFhZGFwdGVyKSByZXR1cm4gbnVsbDtcbiAgdHJ5IHtcbiAgICBjb25zdCByb3cgPSBhd2FpdCBhZGFwdGVyLmZpbmRPbmUoe1xuICAgICAgbW9kZWw6IFwidXNlclwiLFxuICAgICAgc2VsZWN0OiBbXCJpZFwiLCBcIm5hbWVcIiwgXCJlbWFpbFwiXSxcbiAgICAgIHdoZXJlOiBbeyBmaWVsZCwgdmFsdWUgfV0sXG4gICAgfSk7XG4gICAgaWYgKCFyb3cpIHJldHVybiBudWxsO1xuICAgIHJldHVybiB7XG4gICAgICBpZDogU3RyaW5nKHJvdy5pZCksXG4gICAgICBuYW1lOiB0eXBlb2Ygcm93Lm5hbWUgPT09IFwic3RyaW5nXCIgPyByb3cubmFtZSA6IHVuZGVmaW5lZCxcbiAgICAgIGVtYWlsOiB0eXBlb2Ygcm93LmVtYWlsID09PSBcInN0cmluZ1wiID8gcm93LmVtYWlsIDogdW5kZWZpbmVkLFxuICAgIH07XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBudWxsO1xuICB9XG59O1xuXG5jb25zdCBpc05vbkVtcHR5U3RyaW5nID0gKHY6IHVua25vd24pOiB2IGlzIHN0cmluZyA9PiB0eXBlb2YgdiA9PT0gXCJzdHJpbmdcIiAmJiB2Lmxlbmd0aCA+IDA7XG5cbi8vIGRhc2gg7KCc6rGwIOyLnCDtlajqu5gg7IKs65287KeEIGxvY2F0aW9uIOqzteq4iSDqsr3roZzrpbwg64yA7LK07ZWc64ukLlxuLy8g7Jqw7ISg7Iic7JyEOiBjZi1jb25uZWN0aW5nLWlwID4geC1mb3J3YXJkZWQtZm9yKOyyqyDtla3rqqkpID4geC1yZWFsLWlwID4geC12ZXJjZWwtZm9yd2FyZGVkLWZvclxuLy8gKHNvbmFtdS50cyBJUF9IRUFERVJTIOyDgeyImOyZgCDrj5nsnbwpXG5jb25zdCBJUF9IRUFERVJfT1JERVIgPSBbXG4gIFwiY2YtY29ubmVjdGluZy1pcFwiLFxuICBcIngtZm9yd2FyZGVkLWZvclwiLFxuICBcIngtcmVhbC1pcFwiLFxuICBcIngtdmVyY2VsLWZvcndhcmRlZC1mb3JcIixcbl0gYXMgY29uc3Q7XG5cbmNvbnN0IHJlYWRIZWFkZXIgPSAoaGVhZGVyczogdW5rbm93biwga2V5OiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsID0+IHtcbiAgaWYgKCFoZWFkZXJzKSByZXR1cm4gbnVsbDtcbiAgaWYgKGhlYWRlcnMgaW5zdGFuY2VvZiBIZWFkZXJzKSB7XG4gICAgcmV0dXJuIGhlYWRlcnMuZ2V0KGtleSk7XG4gIH1cbiAgaWYgKHR5cGVvZiBoZWFkZXJzID09PSBcIm9iamVjdFwiKSB7XG4gICAgY29uc3QgbWFwID0gaGVhZGVycyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBjb25zdCB2ID0gbWFwW2tleV0gPz8gbWFwW2tleS50b0xvd2VyQ2FzZSgpXTtcbiAgICBpZiAodHlwZW9mIHYgPT09IFwic3RyaW5nXCIpIHJldHVybiB2O1xuICAgIGlmIChBcnJheS5pc0FycmF5KHYpICYmIHR5cGVvZiB2WzBdID09PSBcInN0cmluZ1wiKSByZXR1cm4gdlswXTtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn07XG5cbmNvbnN0IGV4dHJhY3RMb2NhdGlvbkZyb21IZWFkZXJzID0gKGhlYWRlcnM6IHVua25vd24pOiBCdWlsZGVyTG9jYXRpb24gPT4ge1xuICBsZXQgaXBBZGRyZXNzOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgZm9yIChjb25zdCBrZXkgb2YgSVBfSEVBREVSX09SREVSKSB7XG4gICAgY29uc3QgcmF3ID0gcmVhZEhlYWRlcihoZWFkZXJzLCBrZXkpO1xuICAgIGlmICh0eXBlb2YgcmF3ID09PSBcInN0cmluZ1wiICYmIHJhdy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBmaXJzdCA9IHJhdy5zcGxpdChcIixcIilbMF0/LnRyaW0oKTtcbiAgICAgIGlmIChmaXJzdCkge1xuICAgICAgICBpcEFkZHJlc3MgPSBmaXJzdDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGNvbnN0IGNvdW50cnlDb2RlID0gcmVhZEhlYWRlcihoZWFkZXJzLCBcImNmLWlwY291bnRyeVwiKTtcbiAgY29uc3QgY2l0eSA9IHJlYWRIZWFkZXIoaGVhZGVycywgXCJjZi1pcGNpdHlcIik7XG4gIHJldHVybiB7XG4gICAgaXBBZGRyZXNzOiBpcEFkZHJlc3MgPz8gdW5kZWZpbmVkLFxuICAgIGNpdHk6IGNpdHkgPz8gdW5kZWZpbmVkLFxuICAgIGNvdW50cnk6IHVuZGVmaW5lZCxcbiAgICBjb3VudHJ5Q29kZTogY291bnRyeUNvZGUgPz8gdW5kZWZpbmVkLFxuICB9O1xufTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gT3JnYW5pemF0aW9uIGhvb2sg656Y7ZWRIO2XrO2NvFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxudHlwZSBPcmdIb29rRm4gPSAoLi4uYXJnczogdW5rbm93bltdKSA9PiBQcm9taXNlPHVua25vd24+O1xuXG4vLyDso7zslrTsp4Qgb3JnYW5pemF0aW9uSG9va3Mg66CI7L2U65Oc7JeQIOuMgO2VtCDtlbTri7kgbmFtZeydmCDquLDsobQgaG9va+ydhCBjaGFpbu2VnOuLpC5cbi8vIGhhbmRsZXLripQgcGF5bG9hZCDqsJ3ssrQo7LKrIOuyiOynuCDsnbjsnpAp66eMIOuwm+yVhOyEnCBhdWRpdCBlbWl07J2EIOyImO2Wie2VnOuLpC5cbmNvbnN0IHdyYXBPcmdIb29rID0gPFBheWxvYWQ+KFxuICBob29rczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIG5hbWU6IHN0cmluZyxcbiAgaGFuZGxlcjogKHBheWxvYWQ6IFBheWxvYWQpID0+IFByb21pc2U8dm9pZD4sXG4pOiB2b2lkID0+IHtcbiAgY29uc3QgcHJldiA9IGhvb2tzW25hbWVdIGFzIE9yZ0hvb2tGbiB8IHVuZGVmaW5lZDtcbiAgaG9va3NbbmFtZV0gPSBhc3luYyAoLi4uYXJnczogdW5rbm93bltdKTogUHJvbWlzZTx1bmtub3duPiA9PiB7XG4gICAgYXdhaXQgaGFuZGxlcihhcmdzWzBdIGFzIFBheWxvYWQpO1xuICAgIGlmIChwcmV2KSByZXR1cm4gcHJldiguLi5hcmdzKTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9O1xufTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUGx1Z2luIGVudHJ5XG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vKipcbiAqIEJldHRlciBBdXRoIGRhdGFiYXNlSG9va3Mvb3JnYW5pemF0aW9uSG9va3MvbWlkZGxld2FyZeyXkOyEnCDsiJjsp5HtlZxcbiAqIOydtOuypO2KuOulvCBgREIuZ2V0REIoXCJ3XCIpYOuhnCDslrvsnYAga25leOyXkCBgaW5nZXN0QXVkaXRFdmVudGDroZwg7KCB7J6s7ZWc64ukLlxuICpcbiAqIC0gZGFzaChAYmV0dGVyLWF1dGgvaW5mcmEp7J2YIGF1ZGl0LWV2ZW50IOyImOynkSDtm4Ug6rWs7KGw66W8IOywuOqzoO2VtCBTb25hbXUg64K067aAIOyggeyerCDqsr3roZzroZwg7Y+s7YyF7ZWc64ukLlxuICogLSBkYXNo7J2YIGluZnJhIOyXsOqysC9BUEkgZW5kcG9pbnQg7KCc6rO1IOuylOychOuKlCDtj6ztlajtlZjsp4Ag7JWK6rOgLCBhdWRpdC1ldmVudCBlbWl0L2luZ2VzdCDqsr3roZzrp4wg7Jyg7KeA7ZWc64ukLlxuICogLSBzZWN1cml0eSA07KKF7J2AIFIxIOqysOygleyXkCDrlLDrnbwgc2NvcGUgb3V0IChidWlsZGVycy50c+ydmCBUT0RPIOyjvOyEnSDssLjsobApLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc29uYW11QXVkaXRMb2coKTogQmV0dGVyQXV0aFBsdWdpbiB7XG4gIGNvbnN0IGxvZ2dlciA9IGdldExvZ2dlcihbXCJzb25hbXVcIiwgXCJhdWRpdC1sb2dcIl0pO1xuICBjb25zdCBjYXRhbG9nID0gYnVpbGRBdWRpdEV2ZW50Q2F0YWxvZygpO1xuXG4gIC8vIGRhc2ggNzM5NDog64+Z7J28IOyalOyyreyXkOyEnCDshLjshZgg67KM7YGsIOyCreygnOqwgCDri6Ttmowg67Cc7IOd7ZWgIOuVjCBhbGxfc2Vzc2lvbnNfcmV2b2tlZOulvFxuICAvLyDtlZwg67KI66eMIGVtaXTtlZjrj4TroZ0g7LKY66asIOy7qO2FjeyKpO2KuOulvCDquLDslrXtlZzri6QuXG4gIGNvbnN0IHByb2Nlc3NlZEJ1bGtPcGVyYXRpb25Db250ZXh0cyA9IG5ldyBXZWFrU2V0PG9iamVjdD4oKTtcblxuICBjb25zdCBlbWl0ID0gYXN5bmMgKGV2ZW50OiBBdWRpdExvZ0V2ZW50KTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGluZ2VzdEF1ZGl0RXZlbnQoREIuZ2V0REIoXCJ3XCIpLCBldmVudCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoXCJhdWRpdCBldmVudCBpbmdlc3QgZmFpbGVkOiB7ZXJyb3J9XCIsIHsgZXJyb3I6IGVyciB9KTtcbiAgICB9XG4gIH07XG5cbiAgLy8gY3R4LnBhdGggKyBzZXNzaW9u7JeQ7IScIOyCrOyaqeyekCDtirjrpqzqsbDrpbwg64+E7Lac7ZWc64ukKGVudGl0eS5pZOulvCBzdWJqZWN066GcIOyCrOyaqSkuXG4gIGNvbnN0IHRyaWdnZXJGb3IgPSAoY3R4OiBCZXR0ZXJBdXRoUmVxdWVzdEN0eCwgc3ViamVjdFVzZXJJZDogc3RyaW5nKTogQnVpbGRlclRyaWdnZXIgPT5cbiAgICBnZXRUcmlnZ2VySW5mbyhjdHgucGF0aCwgY3R4LmNvbnRleHQuc2Vzc2lvbj8uc2Vzc2lvbj8udXNlcklkID8/IG51bGwsIHN1YmplY3RVc2VySWQpO1xuXG4gIGNvbnN0IGxvY2F0aW9uRm9yID0gKGN0eDogQmV0dGVyQXV0aFJlcXVlc3RDdHgpOiBCdWlsZGVyTG9jYXRpb24gfCB1bmRlZmluZWQgPT5cbiAgICBjdHguY29udGV4dC5sb2NhdGlvbiA/PyB1bmRlZmluZWQ7XG5cbiAgcmV0dXJuIHtcbiAgICBpZDogXCJzb25hbXUtYXVkaXQtbG9nXCIsXG5cbiAgICBpbml0KHBsdWdpbkN0eDogdW5rbm93bikge1xuICAgICAgaW5zdGFsbE9yZ2FuaXphdGlvbkhvb2tzKHBsdWdpbkN0eCwgY2F0YWxvZywgZW1pdCwgbG9nZ2VyKTtcblxuICAgICAgLy8gZGFzaCA3MjgzLTc0NDkg66+465+sOiBkYXRhYmFzZUhvb2tzICh1c2VyL3Nlc3Npb24vYWNjb3VudC92ZXJpZmljYXRpb24pLlxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgb3B0aW9uczoge1xuICAgICAgICAgIGRhdGFiYXNlSG9va3M6IHtcbiAgICAgICAgICAgIHVzZXI6IHtcbiAgICAgICAgICAgICAgY3JlYXRlOiB7XG4gICAgICAgICAgICAgICAgYWZ0ZXI6IGFzeW5jIChyYXdVc2VyOiB1bmtub3duLCByYXdDdHg/OiB1bmtub3duKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBjdHggPSBuYXJyb3dSZXF1ZXN0Q3R4KHJhd0N0eCk7XG4gICAgICAgICAgICAgICAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgY29uc3QgdXNlciA9IHJhd1VzZXIgYXMgVXNlclNuYXBzaG90O1xuICAgICAgICAgICAgICAgICAgYXdhaXQgZW1pdChcbiAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy51c2VyLnRyYWNrVXNlclNpZ25lZFVwKFxuICAgICAgICAgICAgICAgICAgICAgIHVzZXIsXG4gICAgICAgICAgICAgICAgICAgICAgdHJpZ2dlckZvcihjdHgsIHVzZXIuaWQpLFxuICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uRm9yKGN0eCksXG4gICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHVwZGF0ZToge1xuICAgICAgICAgICAgICAgIGFmdGVyOiBhc3luYyAocmF3VXNlcjogdW5rbm93biwgcmF3Q3R4PzogdW5rbm93bik6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgICAgICAgICAgY29uc3QgY3R4ID0gbmFycm93UmVxdWVzdEN0eChyYXdDdHgpO1xuICAgICAgICAgICAgICAgICAgaWYgKCFjdHgpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHVzZXIgPSByYXdVc2VyIGFzIFVzZXJTbmFwc2hvdCAmIHtcbiAgICAgICAgICAgICAgICAgICAgZW1haWxWZXJpZmllZD86IGJvb2xlYW47XG4gICAgICAgICAgICAgICAgICAgIGltYWdlPzogc3RyaW5nIHwgbnVsbDtcbiAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICBjb25zdCBwYXRoID0gY3R4LnBhdGg7XG4gICAgICAgICAgICAgICAgICBjb25zdCB0cmlnZ2VyID0gdHJpZ2dlckZvcihjdHgsIHVzZXIuaWQpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgbG9jYXRpb24gPSBsb2NhdGlvbkZvcihjdHgpO1xuXG4gICAgICAgICAgICAgICAgICBpZiAobWF0Y2hlc0FueVJvdXRlKHBhdGgsIFtST1VURVMuVVBEQVRFX1VTRVIsIFJPVVRFUy5EQVNIX1VQREFURV9VU0VSXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdXBkYXRlZEZpZWxkcyA9IE9iamVjdC5rZXlzKChjdHguYm9keSBhcyBvYmplY3QpID8/IHt9KTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaXNPbmx5SW1hZ2VVcGRhdGUgPVxuICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZWRGaWVsZHMubGVuZ3RoID09PSAxICYmIHVwZGF0ZWRGaWVsZHNbMF0gPT09IFwiaW1hZ2VcIjtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaXNPbmx5RW1haWxWZXJpZmllZFVwZGF0ZSA9XG4gICAgICAgICAgICAgICAgICAgICAgdXBkYXRlZEZpZWxkcy5sZW5ndGggPT09IDEgJiYgdXBkYXRlZEZpZWxkc1swXSA9PT0gXCJlbWFpbFZlcmlmaWVkXCI7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGhhc0VtYWlsVmVyaWZpZWRVcGRhdGUgPSB1cGRhdGVkRmllbGRzLmluY2x1ZGVzKFwiZW1haWxWZXJpZmllZFwiKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGlzT25seUVtYWlsVmVyaWZpZWRVcGRhdGUgJiYgdXNlci5lbWFpbFZlcmlmaWVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZW1pdChjYXRhbG9nLnVzZXIudHJhY2tVc2VyRW1haWxWZXJpZmllZCh1c2VyLCB0cmlnZ2VyLCBsb2NhdGlvbikpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGlzT25seUltYWdlVXBkYXRlICYmIHVzZXIuaW1hZ2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBlbWl0KFxuICAgICAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy51c2VyLnRyYWNrVXNlclByb2ZpbGVJbWFnZVVwZGF0ZWQodXNlciwgdHJpZ2dlciwgbG9jYXRpb24pLFxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzT25seUltYWdlVXBkYXRlICYmICFpc09ubHlFbWFpbFZlcmlmaWVkVXBkYXRlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZW1pdChcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhdGFsb2cudXNlci50cmFja1VzZXJQcm9maWxlVXBkYXRlZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlZEZpZWxkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJpZ2dlcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0VtYWlsVmVyaWZpZWRVcGRhdGUgJiYgdXNlci5lbWFpbFZlcmlmaWVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBlbWl0KGNhdGFsb2cudXNlci50cmFja1VzZXJFbWFpbFZlcmlmaWVkKHVzZXIsIHRyaWdnZXIsIGxvY2F0aW9uKSk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1hdGNoZXNBbnlSb3V0ZShwYXRoLCBbUk9VVEVTLkNIQU5HRV9FTUFJTF0pKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHVwZGF0ZWRGaWVsZHMgPSBPYmplY3Qua2V5cygoY3R4LmJvZHkgYXMgb2JqZWN0KSA/PyB7fSk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy51c2VyLnRyYWNrVXNlclByb2ZpbGVVcGRhdGVkKHVzZXIsIHVwZGF0ZWRGaWVsZHMsIHRyaWdnZXIsIGxvY2F0aW9uKSxcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIGlmIChtYXRjaGVzQW55Um91dGUocGF0aCwgW1JPVVRFUy5WRVJJRllfRU1BSUxdKSAmJiB1c2VyLmVtYWlsVmVyaWZpZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgZW1pdChjYXRhbG9nLnVzZXIudHJhY2tVc2VyRW1haWxWZXJpZmllZCh1c2VyLCB0cmlnZ2VyLCBsb2NhdGlvbikpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICBtYXRjaGVzQW55Um91dGUocGF0aCwgW1JPVVRFUy5BRE1JTl9CQU5fVVNFUl0pICYmXG4gICAgICAgICAgICAgICAgICAgIFwiYmFubmVkXCIgaW4gdXNlciAmJlxuICAgICAgICAgICAgICAgICAgICB1c2VyLmJhbm5lZFxuICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoY2F0YWxvZy51c2VyLnRyYWNrVXNlckJhbm5lZCh1c2VyLCB0cmlnZ2VyLCBsb2NhdGlvbikpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICBtYXRjaGVzQW55Um91dGUocGF0aCwgW1JPVVRFUy5BRE1JTl9VTkJBTl9VU0VSXSkgJiZcbiAgICAgICAgICAgICAgICAgICAgXCJiYW5uZWRcIiBpbiB1c2VyICYmXG4gICAgICAgICAgICAgICAgICAgICF1c2VyLmJhbm5lZFxuICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoY2F0YWxvZy51c2VyLnRyYWNrVXNlclVuQmFubmVkKHVzZXIsIHRyaWdnZXIsIGxvY2F0aW9uKSk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgZGVsZXRlOiB7XG4gICAgICAgICAgICAgICAgYWZ0ZXI6IGFzeW5jIChyYXdVc2VyOiB1bmtub3duLCByYXdDdHg/OiB1bmtub3duKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBjdHggPSBuYXJyb3dSZXF1ZXN0Q3R4KHJhd0N0eCk7XG4gICAgICAgICAgICAgICAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgY29uc3QgdXNlciA9IHJhd1VzZXIgYXMgVXNlclNuYXBzaG90O1xuICAgICAgICAgICAgICAgICAgYXdhaXQgZW1pdChcbiAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy51c2VyLnRyYWNrVXNlckRlbGV0ZWQodXNlciwgdHJpZ2dlckZvcihjdHgsIHVzZXIuaWQpLCBsb2NhdGlvbkZvcihjdHgpKSxcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzZXNzaW9uOiB7XG4gICAgICAgICAgICAgIGNyZWF0ZToge1xuICAgICAgICAgICAgICAgIGJlZm9yZTogYXN5bmMgKFxuICAgICAgICAgICAgICAgICAgcmF3U2Vzc2lvbjogdW5rbm93bixcbiAgICAgICAgICAgICAgICAgIHJhd0N0eD86IHVua25vd24sXG4gICAgICAgICAgICAgICAgKTogUHJvbWlzZTx7IGRhdGE6IHsgbG9naW5NZXRob2Q6IHN0cmluZyB8IG51bGwgfSB9IHwgdW5kZWZpbmVkPiA9PiB7XG4gICAgICAgICAgICAgICAgICB2b2lkIHJhd1Nlc3Npb247XG4gICAgICAgICAgICAgICAgICBjb25zdCBjdHggPSBuYXJyb3dSZXF1ZXN0Q3R4KHJhd0N0eCk7XG4gICAgICAgICAgICAgICAgICBpZiAoIWN0eCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgIHJldHVybiB7IGRhdGE6IHsgbG9naW5NZXRob2Q6IGdldExvZ2luTWV0aG9kKGN0eC5wYXRoLCBjdHgucGFyYW1zPy5pZCkgfSB9O1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgYWZ0ZXI6IGFzeW5jIChyYXdTZXNzaW9uOiB1bmtub3duLCByYXdDdHg/OiB1bmtub3duKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBjdHggPSBuYXJyb3dSZXF1ZXN0Q3R4KHJhd0N0eCk7XG4gICAgICAgICAgICAgICAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgY29uc3Qgc2Vzc2lvbiA9IHJhd1Nlc3Npb24gYXMgU2Vzc2lvblNuYXBzaG90O1xuICAgICAgICAgICAgICAgICAgaWYgKCFzZXNzaW9uLnVzZXJJZCkgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgY29uc3QgbG9jYXRpb24gPSBsb2NhdGlvbkZvcihjdHgpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgbG9naW5NZXRob2QgPSBnZXRMb2dpbk1ldGhvZChjdHgucGF0aCwgY3R4LnBhcmFtcz8uaWQpID8/IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGVucmljaGVkU2Vzc2lvbjogU2Vzc2lvblNuYXBzaG90ID0ge1xuICAgICAgICAgICAgICAgICAgICAuLi5zZXNzaW9uLFxuICAgICAgICAgICAgICAgICAgICBsb2dpbk1ldGhvZDogbG9naW5NZXRob2QgPz8gc2Vzc2lvbi5sb2dpbk1ldGhvZCA/PyBudWxsLFxuICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCBmZXRjaFVzZXJCeShjdHgsIFwiaWRcIiwgc2Vzc2lvbi51c2VySWQpO1xuXG4gICAgICAgICAgICAgICAgICBsZXQgdHJpZ2dlcjogQnVpbGRlclRyaWdnZXI7XG4gICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIG1hdGNoZXNBbnlSb3V0ZShjdHgucGF0aCwgW1xuICAgICAgICAgICAgICAgICAgICAgIFJPVVRFUy5TSUdOX0lOLFxuICAgICAgICAgICAgICAgICAgICAgIFJPVVRFUy5TSUdOX1VQLFxuICAgICAgICAgICAgICAgICAgICAgIFJPVVRFUy5TSUdOX0lOX1NPQ0lBTF9DQUxMQkFDSyxcbiAgICAgICAgICAgICAgICAgICAgICBST1VURVMuU0lHTl9JTl9PQVVUSF9DQUxMQkFDSyxcbiAgICAgICAgICAgICAgICAgICAgXSlcbiAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICB0cmlnZ2VyID0gZ2V0VHJpZ2dlckluZm8oY3R4LnBhdGgsIHNlc3Npb24udXNlcklkLCBzZXNzaW9uLnVzZXJJZCk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy5zZXNzaW9uLnRyYWNrVXNlclNpZ25lZEluKGVucmljaGVkU2Vzc2lvbiwgdXNlciwgdHJpZ2dlciwgbG9jYXRpb24pLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlciA9IHRyaWdnZXJGb3IoY3R4LCBzZXNzaW9uLnVzZXJJZCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBhd2FpdCBlbWl0KFxuICAgICAgICAgICAgICAgICAgICBjYXRhbG9nLnNlc3Npb24udHJhY2tTZXNzaW9uQ3JlYXRlZChlbnJpY2hlZFNlc3Npb24sIHVzZXIsIHRyaWdnZXIsIGxvY2F0aW9uKSxcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICBpZiAoaXNOb25FbXB0eVN0cmluZyhzZXNzaW9uLmltcGVyc29uYXRlZEJ5KSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpbXBlcnNvbmF0b3IgPSBhd2FpdCBmZXRjaFVzZXJCeShjdHgsIFwiaWRcIiwgc2Vzc2lvbi5pbXBlcnNvbmF0ZWRCeSk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy5zZXNzaW9uLnRyYWNrVXNlckltcGVyc29uYXRlZChcbiAgICAgICAgICAgICAgICAgICAgICAgIGVucmljaGVkU2Vzc2lvbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHVzZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBpbXBlcnNvbmF0b3IsXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRyaWdnZXJlZEJ5OiBzZXNzaW9uLmltcGVyc29uYXRlZEJ5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB0cmlnZ2VyQ29udGV4dDogdHJpZ2dlci50cmlnZ2VyQ29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGRlbGV0ZToge1xuICAgICAgICAgICAgICAgIGFmdGVyOiBhc3luYyAocmF3U2Vzc2lvbjogdW5rbm93biwgcmF3Q3R4PzogdW5rbm93bik6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgICAgICAgICAgY29uc3QgY3R4ID0gbmFycm93UmVxdWVzdEN0eChyYXdDdHgpO1xuICAgICAgICAgICAgICAgICAgaWYgKCFjdHgpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHNlc3Npb24gPSByYXdTZXNzaW9uIGFzIFNlc3Npb25TbmFwc2hvdDtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGxvY2F0aW9uID0gbG9jYXRpb25Gb3IoY3R4KTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGVucmljaGVkU2Vzc2lvbjogU2Vzc2lvblNuYXBzaG90ID0geyAuLi5zZXNzaW9uIH07XG4gICAgICAgICAgICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgZmV0Y2hVc2VyQnkoY3R4LCBcImlkXCIsIHNlc3Npb24udXNlcklkKTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHRyaWdnZXIgPSB0cmlnZ2VyRm9yKGN0eCwgc2Vzc2lvbi51c2VySWQpO1xuICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICBtYXRjaGVzQW55Um91dGUoY3R4LnBhdGgsIFtcbiAgICAgICAgICAgICAgICAgICAgICBST1VURVMuUkVWT0tFX0FMTF9TRVNTSU9OUyxcbiAgICAgICAgICAgICAgICAgICAgICBST1VURVMuQURNSU5fUkVWT0tFX1VTRVJfU0VTU0lPTlMsXG4gICAgICAgICAgICAgICAgICAgICAgUk9VVEVTLkRBU0hfUkVWT0tFX1NFU1NJT05TX0FMTCxcbiAgICAgICAgICAgICAgICAgICAgICBST1VURVMuREFTSF9CQU5fVVNFUixcbiAgICAgICAgICAgICAgICAgICAgXSlcbiAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXByb2Nlc3NlZEJ1bGtPcGVyYXRpb25Db250ZXh0cy5oYXMoY3R4KSkge1xuICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXRhbG9nLnNlc3Npb24udHJhY2tTZXNzaW9uUmV2b2tlZEFsbChlbnJpY2hlZFNlc3Npb24sIHVzZXIsIHRyaWdnZXIpLFxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgcHJvY2Vzc2VkQnVsa09wZXJhdGlvbkNvbnRleHRzLmFkZChjdHgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1hdGNoZXNBbnlSb3V0ZShjdHgucGF0aCwgW1JPVVRFUy5TSUdOX09VVF0pKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy5zZXNzaW9uLnRyYWNrVXNlclNpZ25lZE91dChlbnJpY2hlZFNlc3Npb24sIHVzZXIsIHRyaWdnZXIsIGxvY2F0aW9uKSxcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy5zZXNzaW9uLnRyYWNrU2Vzc2lvblJldm9rZWQoZW5yaWNoZWRTZXNzaW9uLCB1c2VyLCB0cmlnZ2VyLCBsb2NhdGlvbiksXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBpZiAoaXNOb25FbXB0eVN0cmluZyhzZXNzaW9uLmltcGVyc29uYXRlZEJ5KSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpbXBlcnNvbmF0b3IgPSBhd2FpdCBmZXRjaFVzZXJCeShjdHgsIFwiaWRcIiwgc2Vzc2lvbi5pbXBlcnNvbmF0ZWRCeSk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy5zZXNzaW9uLnRyYWNrVXNlckltcGVyc29uYXRpb25TdG9wKFxuICAgICAgICAgICAgICAgICAgICAgICAgZW5yaWNoZWRTZXNzaW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgdXNlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGltcGVyc29uYXRvcixcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyaWdnZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYWNjb3VudDoge1xuICAgICAgICAgICAgICBjcmVhdGU6IHtcbiAgICAgICAgICAgICAgICBhZnRlcjogYXN5bmMgKHJhd0FjY291bnQ6IHVua25vd24sIHJhd0N0eD86IHVua25vd24pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGN0eCA9IG5hcnJvd1JlcXVlc3RDdHgocmF3Q3R4KTtcbiAgICAgICAgICAgICAgICAgIGlmICghY3R4KSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBjb25zdCBhY2NvdW50ID0gcmF3QWNjb3VudCBhcyBBY2NvdW50U25hcHNob3Q7XG4gICAgICAgICAgICAgICAgICBpZiAoIWFjY291bnQudXNlcklkKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgZmV0Y2hVc2VyQnkoY3R4LCBcImlkXCIsIGFjY291bnQudXNlcklkKTtcbiAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgIGNhdGFsb2cuYWNjb3VudC50cmFja0FjY291bnRMaW5raW5nKFxuICAgICAgICAgICAgICAgICAgICAgIGFjY291bnQsXG4gICAgICAgICAgICAgICAgICAgICAgdXNlcixcbiAgICAgICAgICAgICAgICAgICAgICB0cmlnZ2VyRm9yKGN0eCwgYWNjb3VudC51c2VySWQpLFxuICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uRm9yKGN0eCksXG4gICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHVwZGF0ZToge1xuICAgICAgICAgICAgICAgIGFmdGVyOiBhc3luYyAocmF3QWNjb3VudDogdW5rbm93biwgcmF3Q3R4PzogdW5rbm93bik6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgICAgICAgICAgY29uc3QgY3R4ID0gbmFycm93UmVxdWVzdEN0eChyYXdDdHgpO1xuICAgICAgICAgICAgICAgICAgaWYgKCFjdHgpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGFjY291bnQgPSByYXdBY2NvdW50IGFzIEFjY291bnRTbmFwc2hvdDtcbiAgICAgICAgICAgICAgICAgIGlmICghYWNjb3VudC51c2VySWQpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgIW1hdGNoZXNBbnlSb3V0ZShjdHgucGF0aCwgW1xuICAgICAgICAgICAgICAgICAgICAgIFJPVVRFUy5DSEFOR0VfUEFTU1dPUkQsXG4gICAgICAgICAgICAgICAgICAgICAgUk9VVEVTLlNFVF9QQVNTV09SRCxcbiAgICAgICAgICAgICAgICAgICAgICBST1VURVMuUkVTRVRfUEFTU1dPUkQsXG4gICAgICAgICAgICAgICAgICAgICAgUk9VVEVTLkFETUlOX1NFVF9QQVNTV09SRCxcbiAgICAgICAgICAgICAgICAgICAgXSlcbiAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgZmV0Y2hVc2VyQnkoY3R4LCBcImlkXCIsIGFjY291bnQudXNlcklkKTtcbiAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgIGNhdGFsb2cuYWNjb3VudC50cmFja0FjY291bnRQYXNzd29yZENoYW5nZShcbiAgICAgICAgICAgICAgICAgICAgICBhY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAgIHVzZXIsXG4gICAgICAgICAgICAgICAgICAgICAgdHJpZ2dlckZvcihjdHgsIGFjY291bnQudXNlcklkKSxcbiAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbkZvcihjdHgpLFxuICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBkZWxldGU6IHtcbiAgICAgICAgICAgICAgICBhZnRlcjogYXN5bmMgKHJhd0FjY291bnQ6IHVua25vd24sIHJhd0N0eD86IHVua25vd24pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGN0eCA9IG5hcnJvd1JlcXVlc3RDdHgocmF3Q3R4KTtcbiAgICAgICAgICAgICAgICAgIGlmICghY3R4KSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBjb25zdCBhY2NvdW50ID0gcmF3QWNjb3VudCBhcyBBY2NvdW50U25hcHNob3Q7XG4gICAgICAgICAgICAgICAgICBpZiAoIWFjY291bnQudXNlcklkKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgZmV0Y2hVc2VyQnkoY3R4LCBcImlkXCIsIGFjY291bnQudXNlcklkKTtcbiAgICAgICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgICAgIGNhdGFsb2cuYWNjb3VudC50cmFja0FjY291bnRVbmxpbmsoXG4gICAgICAgICAgICAgICAgICAgICAgYWNjb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICB1c2VyLFxuICAgICAgICAgICAgICAgICAgICAgIHRyaWdnZXJGb3IoY3R4LCBhY2NvdW50LnVzZXJJZCksXG4gICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25Gb3IoY3R4KSxcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB2ZXJpZmljYXRpb246IHtcbiAgICAgICAgICAgICAgY3JlYXRlOiB7XG4gICAgICAgICAgICAgICAgYWZ0ZXI6IGFzeW5jIChyYXdWZXJpZmljYXRpb246IHVua25vd24sIHJhd0N0eD86IHVua25vd24pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGN0eCA9IG5hcnJvd1JlcXVlc3RDdHgocmF3Q3R4KTtcbiAgICAgICAgICAgICAgICAgIGlmICghY3R4KSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBpZiAoIW1hdGNoZXNBbnlSb3V0ZShjdHgucGF0aCwgW1JPVVRFUy5SRVFVRVNUX1BBU1NXT1JEX1JFU0VUXSkpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IHJhd1ZlcmlmaWNhdGlvbiBhcyBWZXJpZmljYXRpb25TbmFwc2hvdDtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHNlc3Npb25Vc2VySWQgPSBjdHguY29udGV4dC5zZXNzaW9uPy51c2VyPy5pZCA/PyBcInVua25vd25cIjtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHRyaWdnZXIgPSBnZXRUcmlnZ2VySW5mbyhjdHgucGF0aCwgc2Vzc2lvblVzZXJJZCwgc2Vzc2lvblVzZXJJZCk7XG4gICAgICAgICAgICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgZmV0Y2hVc2VyQnkoY3R4LCBcImlkXCIsIHZlcmlmaWNhdGlvbi52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICBhd2FpdCBlbWl0KFxuICAgICAgICAgICAgICAgICAgICBjYXRhbG9nLnZlcmlmaWNhdGlvbi50cmFja1Bhc3N3b3JkUmVzZXRSZXF1ZXN0KFxuICAgICAgICAgICAgICAgICAgICAgIHZlcmlmaWNhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICB1c2VyLFxuICAgICAgICAgICAgICAgICAgICAgIHRyaWdnZXIsXG4gICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25Gb3IoY3R4KSxcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgZGVsZXRlOiB7XG4gICAgICAgICAgICAgICAgYWZ0ZXI6IGFzeW5jIChyYXdWZXJpZmljYXRpb246IHVua25vd24sIHJhd0N0eD86IHVua25vd24pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGN0eCA9IG5hcnJvd1JlcXVlc3RDdHgocmF3Q3R4KTtcbiAgICAgICAgICAgICAgICAgIGlmICghY3R4KSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBpZiAoIW1hdGNoZXNBbnlSb3V0ZShjdHgucGF0aCwgW1JPVVRFUy5SRVNFVF9QQVNTV09SRF0pKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBjb25zdCB2ZXJpZmljYXRpb24gPSByYXdWZXJpZmljYXRpb24gYXMgVmVyaWZpY2F0aW9uU25hcHNob3Q7XG4gICAgICAgICAgICAgICAgICBjb25zdCBzZXNzaW9uVXNlcklkID0gY3R4LmNvbnRleHQuc2Vzc2lvbj8udXNlcj8uaWQgPz8gXCJ1bmtub3duXCI7XG4gICAgICAgICAgICAgICAgICBjb25zdCB0cmlnZ2VyID0gZ2V0VHJpZ2dlckluZm8oY3R4LnBhdGgsIHNlc3Npb25Vc2VySWQsIHNlc3Npb25Vc2VySWQpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgdXNlciA9IGF3YWl0IGZldGNoVXNlckJ5KGN0eCwgXCJpZFwiLCB2ZXJpZmljYXRpb24udmFsdWUpO1xuICAgICAgICAgICAgICAgICAgYXdhaXQgZW1pdChcbiAgICAgICAgICAgICAgICAgICAgY2F0YWxvZy52ZXJpZmljYXRpb24udHJhY2tQYXNzd29yZFJlc2V0UmVxdWVzdENvbXBsZXRpb24oXG4gICAgICAgICAgICAgICAgICAgICAgdmVyaWZpY2F0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgIHVzZXIsXG4gICAgICAgICAgICAgICAgICAgICAgdHJpZ2dlcixcbiAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbkZvcihjdHgpLFxuICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9LFxuXG4gICAgaG9va3M6IHtcbiAgICAgIGJlZm9yZTogW1xuICAgICAgICB7XG4gICAgICAgICAgLy8gZGFzaCDsoJzqsbDroZwg7IKs65287KeEIGxvY2F0aW9uIOqzteq4iSDqsr3roZzrpbwg67O16rWs7ZWc64ukLlxuICAgICAgICAgIC8vIOuqqOuToCDsmpTssq3sl5DshJwgY3R4LmNvbnRleHQubG9jYXRpb27snYQg7LGE7JuMIOydtO2bhCDruYzrjZTrk6TsnbQgaXBBZGRyZXNzL2NpdHkvY291bnRyeUNvZGXrpbwg6riw66Gd7ZWgIOyImCDsnojqsowg7ZWc64ukLlxuICAgICAgICAgIG1hdGNoZXI6ICgpID0+IHRydWUsXG4gICAgICAgICAgaGFuZGxlcjogY3JlYXRlQXV0aE1pZGRsZXdhcmUoYXN5bmMgKHJhd0N0eCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgY3R4ID0gcmF3Q3R4IGFzIHtcbiAgICAgICAgICAgICAgaGVhZGVycz86IHVua25vd247XG4gICAgICAgICAgICAgIHJlcXVlc3Q/OiB7IGhlYWRlcnM/OiB1bmtub3duIH0gfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgIGNvbnRleHQ/OiB7IGxvY2F0aW9uPzogQnVpbGRlckxvY2F0aW9uIHwgbnVsbCB9ICYgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKCFjdHguY29udGV4dCkgcmV0dXJuO1xuICAgICAgICAgICAgY29uc3QgaGVhZGVycyA9IGN0eC5oZWFkZXJzID8/IGN0eC5yZXF1ZXN0Py5oZWFkZXJzO1xuICAgICAgICAgICAgY3R4LmNvbnRleHQubG9jYXRpb24gPSBleHRyYWN0TG9jYXRpb25Gcm9tSGVhZGVycyhoZWFkZXJzKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBhZnRlcjogW1xuICAgICAgICB7XG4gICAgICAgICAgLy8gZGFzaCA3NDYyLTc0ODcg66+465+sOiB2ZXJpZmljYXRpb24gZW1haWwgc2VuZCwgc2lnbi1pbiBhdHRlbXB0cy5cbiAgICAgICAgICAvLyBHRVQg7JqU7LKt7J2AIOy9nOuwsSDqsr3roZzrp4wg7Ya16rO87Iuc7YKo64ukLlxuICAgICAgICAgIG1hdGNoZXI6IChjdHg6IHVua25vd24pOiBib29sZWFuID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGMgPSBjdHggYXMgeyByZXF1ZXN0PzogeyBtZXRob2Q/OiBzdHJpbmc7IHVybD86IHN0cmluZyB9IH07XG4gICAgICAgICAgICBpZiAoYy5yZXF1ZXN0Py5tZXRob2QgIT09IFwiR0VUXCIpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgaWYgKCFjLnJlcXVlc3QudXJsKSByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBwID0gbmV3IFVSTChjLnJlcXVlc3QudXJsKS5wYXRobmFtZTtcbiAgICAgICAgICAgICAgcmV0dXJuIG1hdGNoZXNBbnlSb3V0ZShwLCBbXG4gICAgICAgICAgICAgICAgUk9VVEVTLlNJR05fSU5fU09DSUFMX0NBTExCQUNLLFxuICAgICAgICAgICAgICAgIFJPVVRFUy5TSUdOX0lOX09BVVRIX0NBTExCQUNLLFxuICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBoYW5kbGVyOiBjcmVhdGVBdXRoTWlkZGxld2FyZShhc3luYyAocmF3Q3R4KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjdHggPSBuYXJyb3dSZXF1ZXN0Q3R4KHJhd0N0eCk7XG4gICAgICAgICAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgICAgICAgICAgY29uc3Qgc2Vzc2lvblVzZXIgPSBjdHguY29udGV4dC5zZXNzaW9uPy51c2VyO1xuICAgICAgICAgICAgY29uc3Qgc2Vzc2lvblVzZXJJZCA9IHNlc3Npb25Vc2VyPy5pZCA/PyBcInVua25vd25cIjtcbiAgICAgICAgICAgIGNvbnN0IHRyaWdnZXIgPSBnZXRUcmlnZ2VySW5mbyhjdHgucGF0aCwgc2Vzc2lvblVzZXJJZCwgc2Vzc2lvblVzZXJJZCk7XG4gICAgICAgICAgICBjb25zdCBsb2NhdGlvbiA9IGxvY2F0aW9uRm9yKGN0eCk7XG4gICAgICAgICAgICBjb25zdCByZXR1cm5lZCA9IGN0eC5jb250ZXh0LnJldHVybmVkO1xuICAgICAgICAgICAgY29uc3QgaXNFcnJvcmVkID0gcmV0dXJuZWQgaW5zdGFuY2VvZiBFcnJvcjtcblxuICAgICAgICAgICAgLy8gdmVyaWZpY2F0aW9uIGVtYWlsIHNlbnRcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgbWF0Y2hlc0FueVJvdXRlKGN0eC5wYXRoLCBbUk9VVEVTLlNFTkRfVkVSSUZJQ0FUSU9OX0VNQUlMXSkgJiZcbiAgICAgICAgICAgICAgY3R4LmNvbnRleHQuc2Vzc2lvbiAmJlxuICAgICAgICAgICAgICAhaXNFcnJvcmVkXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgY29uc3Qgc2Vzc2lvbkVudGl0eSA9IGN0eC5jb250ZXh0LnNlc3Npb24uc2Vzc2lvbiBhcyBTZXNzaW9uU25hcHNob3QgfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgIGNvbnN0IHVzZXIgPSBjdHguY29udGV4dC5zZXNzaW9uLnVzZXIgYXNcbiAgICAgICAgICAgICAgICB8IHsgbmFtZT86IHN0cmluZzsgZW1haWw/OiBzdHJpbmcgfVxuICAgICAgICAgICAgICAgIHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgICBpZiAoc2Vzc2lvbkVudGl0eSAmJiB1c2VyKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgZW1pdChcbiAgICAgICAgICAgICAgICAgIGNhdGFsb2cuc2Vzc2lvbi50cmFja0VtYWlsVmVyaWZpY2F0aW9uU2VudChzZXNzaW9uRW50aXR5LCB1c2VyLCB0cmlnZ2VyKSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IGJvZHkgPVxuICAgICAgICAgICAgICAoY3R4LmJvZHkgYXMgeyBlbWFpbD86IHN0cmluZzsgcHJvdmlkZXI/OiBzdHJpbmc7IGlkVG9rZW4/OiBzdHJpbmcgfSB8IG51bGwpID8/IG51bGw7XG4gICAgICAgICAgICAvLyBlbWFpbCBzaWduLWluIGF0dGVtcHQgZmFpbGVkXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIG1hdGNoZXNBbnlSb3V0ZShjdHgucGF0aCwgW1JPVVRFUy5TSUdOX0lOX0VNQUlMLCBST1VURVMuU0lHTl9JTl9FTUFJTF9PVFBdKSAmJlxuICAgICAgICAgICAgICBpc0Vycm9yZWQgJiZcbiAgICAgICAgICAgICAgYm9keT8uZW1haWxcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgZmV0Y2hVc2VyQnkoY3R4LCBcImVtYWlsXCIsIGJvZHkuZW1haWwpO1xuICAgICAgICAgICAgICBhd2FpdCBlbWl0KFxuICAgICAgICAgICAgICAgIGNhdGFsb2cuc2Vzc2lvbi50cmFja0VtYWlsU2lnbkluQXR0ZW1wdChcbiAgICAgICAgICAgICAgICAgIHsgZW1haWw6IGJvZHkuZW1haWwsIGxvZ2luTWV0aG9kOiBnZXRMb2dpbk1ldGhvZChjdHgucGF0aCwgY3R4LnBhcmFtcz8uaWQpIH0sXG4gICAgICAgICAgICAgICAgICB1c2VyLFxuICAgICAgICAgICAgICAgICAgdHJpZ2dlcixcbiAgICAgICAgICAgICAgICAgIGxvY2F0aW9uLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBzb2NpYWwgc2lnbi1pbiBhdHRlbXB0IGZhaWxlZCAoUE9TVClcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgbWF0Y2hlc0FueVJvdXRlKGN0eC5wYXRoLCBbUk9VVEVTLlNJR05fSU5fU09DSUFMXSkgJiZcbiAgICAgICAgICAgICAgaXNFcnJvcmVkICYmXG4gICAgICAgICAgICAgIGJvZHk/LnByb3ZpZGVyICYmXG4gICAgICAgICAgICAgIGJvZHk/LmlkVG9rZW5cbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICBhd2FpdCBlbWl0KFxuICAgICAgICAgICAgICAgIGNhdGFsb2cuc2Vzc2lvbi50cmFja1NvY2lhbFNpZ25JbkF0dGVtcHQoXG4gICAgICAgICAgICAgICAgICB7IGxvZ2luTWV0aG9kOiBnZXRMb2dpbk1ldGhvZChjdHgucGF0aCwgY3R4LnBhcmFtcz8uaWQpIH0sXG4gICAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgICAgdHJpZ2dlcixcbiAgICAgICAgICAgICAgICAgIGxvY2F0aW9uLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBzb2NpYWwgcmVkaXJlY3Rpb24gY2FsbGJhY2sgZmFpbGVkIChHRVQpXG4gICAgICAgICAgICBpZiAobWF0Y2hlc0FueVJvdXRlKGN0eC5wYXRoLCBbUk9VVEVTLlNJR05fSU5fU09DSUFMX0NBTExCQUNLXSkgJiYgaXNFcnJvcmVkKSB7XG4gICAgICAgICAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgICAgICAgICAgY2F0YWxvZy5zZXNzaW9uLnRyYWNrU29jaWFsU2lnbkluUmVkaXJlY3Rpb25BdHRlbXB0KFxuICAgICAgICAgICAgICAgICAgeyBsb2dpbk1ldGhvZDogZ2V0TG9naW5NZXRob2QoY3R4LnBhdGgsIGN0eC5wYXJhbXM/LmlkKSB9LFxuICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgIHRyaWdnZXIsXG4gICAgICAgICAgICAgICAgICBsb2NhdGlvbixcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9LFxuICB9O1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBPcmdhbml6YXRpb24gaG9vayDtlanshLEgKG9yZ2FuaXphdGlvbiDtlIzrn6zqt7jsnbjsnbQg7Zmc7ISx7ZmU65CcIOqyveyasOyXkOunjClcbi8vIGRhc2ggNzE5Mi03MjgxIOuvuOufrC5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbnR5cGUgRXZlbnRFbWl0dGVyID0gKGV2ZW50OiBBdWRpdExvZ0V2ZW50KSA9PiBQcm9taXNlPHZvaWQ+O1xudHlwZSBBdWRpdExvZ2dlciA9IFJldHVyblR5cGU8dHlwZW9mIGdldExvZ2dlcj47XG5cbmZ1bmN0aW9uIGluc3RhbGxPcmdhbml6YXRpb25Ib29rcyhcbiAgcGx1Z2luQ3R4OiB1bmtub3duLFxuICBjYXRhbG9nOiBSZXR1cm5UeXBlPHR5cGVvZiBidWlsZEF1ZGl0RXZlbnRDYXRhbG9nPixcbiAgZW1pdDogRXZlbnRFbWl0dGVyLFxuICBsb2dnZXI6IEF1ZGl0TG9nZ2VyLFxuKTogdm9pZCB7XG4gIGNvbnN0IGdldFBsdWdpbiA9IChwbHVnaW5DdHggYXMgeyBnZXRQbHVnaW4/OiAoaWQ6IHN0cmluZykgPT4gdW5rbm93biB9KT8uZ2V0UGx1Z2luO1xuICBjb25zdCBvcmdhbml6YXRpb25QbHVnaW4gPVxuICAgIHR5cGVvZiBnZXRQbHVnaW4gPT09IFwiZnVuY3Rpb25cIiA/IGdldFBsdWdpbi5jYWxsKHBsdWdpbkN0eCwgXCJvcmdhbml6YXRpb25cIikgOiBudWxsO1xuXG4gIGlmICghb3JnYW5pemF0aW9uUGx1Z2luIHx8IHR5cGVvZiBvcmdhbml6YXRpb25QbHVnaW4gIT09IFwib2JqZWN0XCIpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJvcmdhbml6YXRpb24gcGx1Z2luIG5vdCBhY3RpdmU7IHNraXBwaW5nIGluc3RydW1lbnRhdGlvblwiKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBvcmdQbHVnaW4gPSBvcmdhbml6YXRpb25QbHVnaW4gYXMge1xuICAgIG9wdGlvbnM/OiB7IG9yZ2FuaXphdGlvbkhvb2tzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfTtcbiAgfTtcbiAgb3JnUGx1Z2luLm9wdGlvbnMgPSBvcmdQbHVnaW4ub3B0aW9ucyA/PyB7fTtcbiAgY29uc3QgaG9va3MgPSAob3JnUGx1Z2luLm9wdGlvbnMub3JnYW5pemF0aW9uSG9va3MgPSBvcmdQbHVnaW4ub3B0aW9ucy5vcmdhbml6YXRpb25Ib29rcyA/PyB7fSk7XG5cbiAgd3JhcE9yZ0hvb2s8eyBvcmdhbml6YXRpb246IE9yZ2FuaXphdGlvblNuYXBzaG90OyB1c2VyOiBVc2VyU25hcHNob3QgfT4oXG4gICAgaG9va3MsXG4gICAgXCJhZnRlckNyZWF0ZU9yZ2FuaXphdGlvblwiLFxuICAgIGFzeW5jIChwKSA9PlxuICAgICAgZW1pdChcbiAgICAgICAgY2F0YWxvZy5vcmdhbml6YXRpb24udHJhY2tPcmdhbml6YXRpb25DcmVhdGVkKFxuICAgICAgICAgIHAub3JnYW5pemF0aW9uLFxuICAgICAgICAgIGdldE9yZ2FuaXphdGlvblRyaWdnZXJJbmZvKHAudXNlciksXG4gICAgICAgICksXG4gICAgICApLFxuICApO1xuXG4gIHdyYXBPcmdIb29rPHsgb3JnYW5pemF0aW9uPzogT3JnYW5pemF0aW9uU25hcHNob3Q7IHVzZXI6IFVzZXJTbmFwc2hvdCB9PihcbiAgICBob29rcyxcbiAgICBcImFmdGVyVXBkYXRlT3JnYW5pemF0aW9uXCIsXG4gICAgYXN5bmMgKHApID0+IHtcbiAgICAgIGlmICghcC5vcmdhbml6YXRpb24pIHJldHVybjtcbiAgICAgIGF3YWl0IGVtaXQoXG4gICAgICAgIGNhdGFsb2cub3JnYW5pemF0aW9uLnRyYWNrT3JnYW5pemF0aW9uVXBkYXRlZChcbiAgICAgICAgICBwLm9yZ2FuaXphdGlvbixcbiAgICAgICAgICBnZXRPcmdhbml6YXRpb25UcmlnZ2VySW5mbyhwLnVzZXIpLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICB9LFxuICApO1xuXG4gIHdyYXBPcmdIb29rPHtcbiAgICBvcmdhbml6YXRpb246IE9yZ2FuaXphdGlvblNuYXBzaG90O1xuICAgIG1lbWJlcjogTWVtYmVyU25hcHNob3Q7XG4gICAgdXNlcjogVXNlclNuYXBzaG90O1xuICB9Pihob29rcywgXCJhZnRlckFkZE1lbWJlclwiLCBhc3luYyAocCkgPT5cbiAgICBlbWl0KFxuICAgICAgY2F0YWxvZy5tZW1iZXIudHJhY2tPcmdhbml6YXRpb25NZW1iZXJBZGRlZChcbiAgICAgICAgcC5vcmdhbml6YXRpb24sXG4gICAgICAgIHAubWVtYmVyLFxuICAgICAgICBwLnVzZXIsXG4gICAgICAgIGdldE9yZ2FuaXphdGlvblRyaWdnZXJJbmZvKHAudXNlciksXG4gICAgICApLFxuICAgICksXG4gICk7XG5cbiAgd3JhcE9yZ0hvb2s8e1xuICAgIG9yZ2FuaXphdGlvbjogT3JnYW5pemF0aW9uU25hcHNob3Q7XG4gICAgbWVtYmVyOiBNZW1iZXJTbmFwc2hvdDtcbiAgICB1c2VyOiBVc2VyU25hcHNob3Q7XG4gIH0+KGhvb2tzLCBcImFmdGVyUmVtb3ZlTWVtYmVyXCIsIGFzeW5jIChwKSA9PlxuICAgIGVtaXQoXG4gICAgICBjYXRhbG9nLm1lbWJlci50cmFja09yZ2FuaXphdGlvbk1lbWJlclJlbW92ZWQoXG4gICAgICAgIHAub3JnYW5pemF0aW9uLFxuICAgICAgICBwLm1lbWJlcixcbiAgICAgICAgcC51c2VyLFxuICAgICAgICBnZXRPcmdhbml6YXRpb25UcmlnZ2VySW5mbyhwLnVzZXIpLFxuICAgICAgKSxcbiAgICApLFxuICApO1xuXG4gIHdyYXBPcmdIb29rPHtcbiAgICBvcmdhbml6YXRpb246IE9yZ2FuaXphdGlvblNuYXBzaG90O1xuICAgIG1lbWJlcjogTWVtYmVyU25hcHNob3Q7XG4gICAgdXNlcjogVXNlclNuYXBzaG90O1xuICAgIHByZXZpb3VzUm9sZTogc3RyaW5nO1xuICB9Pihob29rcywgXCJhZnRlclVwZGF0ZU1lbWJlclJvbGVcIiwgYXN5bmMgKHApID0+XG4gICAgZW1pdChcbiAgICAgIGNhdGFsb2cubWVtYmVyLnRyYWNrT3JnYW5pemF0aW9uTWVtYmVyUm9sZVVwZGF0ZWQoXG4gICAgICAgIHAub3JnYW5pemF0aW9uLFxuICAgICAgICBwLm1lbWJlcixcbiAgICAgICAgcC51c2VyLFxuICAgICAgICBwLnByZXZpb3VzUm9sZSxcbiAgICAgICAgZ2V0T3JnYW5pemF0aW9uVHJpZ2dlckluZm8ocC51c2VyKSxcbiAgICAgICksXG4gICAgKSxcbiAgKTtcblxuICB3cmFwT3JnSG9vazx7XG4gICAgb3JnYW5pemF0aW9uOiBPcmdhbml6YXRpb25TbmFwc2hvdDtcbiAgICBpbnZpdGF0aW9uOiBJbnZpdGF0aW9uU25hcHNob3Q7XG4gICAgaW52aXRlcjogVXNlclNuYXBzaG90O1xuICB9Pihob29rcywgXCJhZnRlckNyZWF0ZUludml0YXRpb25cIiwgYXN5bmMgKHApID0+XG4gICAgZW1pdChcbiAgICAgIGNhdGFsb2cuaW52aXRhdGlvbi50cmFja09yZ2FuaXphdGlvbk1lbWJlckludml0ZWQoXG4gICAgICAgIHAub3JnYW5pemF0aW9uLFxuICAgICAgICBwLmludml0YXRpb24sXG4gICAgICAgIHAuaW52aXRlcixcbiAgICAgICAgZ2V0T3JnYW5pemF0aW9uVHJpZ2dlckluZm8ocC5pbnZpdGVyKSxcbiAgICAgICksXG4gICAgKSxcbiAgKTtcblxuICB3cmFwT3JnSG9vazx7XG4gICAgb3JnYW5pemF0aW9uOiBPcmdhbml6YXRpb25TbmFwc2hvdDtcbiAgICBpbnZpdGF0aW9uOiBJbnZpdGF0aW9uU25hcHNob3Q7XG4gICAgbWVtYmVyOiBNZW1iZXJTbmFwc2hvdDtcbiAgICB1c2VyOiBVc2VyU25hcHNob3Q7XG4gIH0+KGhvb2tzLCBcImFmdGVyQWNjZXB0SW52aXRhdGlvblwiLCBhc3luYyAocCkgPT5cbiAgICBlbWl0KFxuICAgICAgY2F0YWxvZy5pbnZpdGF0aW9uLnRyYWNrT3JnYW5pemF0aW9uTWVtYmVySW52aXRlQWNjZXB0ZWQoXG4gICAgICAgIHAub3JnYW5pemF0aW9uLFxuICAgICAgICBwLmludml0YXRpb24sXG4gICAgICAgIHAubWVtYmVyLFxuICAgICAgICBwLnVzZXIsXG4gICAgICAgIGdldE9yZ2FuaXphdGlvblRyaWdnZXJJbmZvKHAudXNlciksXG4gICAgICApLFxuICAgICksXG4gICk7XG5cbiAgd3JhcE9yZ0hvb2s8e1xuICAgIG9yZ2FuaXphdGlvbjogT3JnYW5pemF0aW9uU25hcHNob3Q7XG4gICAgaW52aXRhdGlvbjogSW52aXRhdGlvblNuYXBzaG90O1xuICAgIHVzZXI6IFVzZXJTbmFwc2hvdDtcbiAgfT4oaG9va3MsIFwiYWZ0ZXJSZWplY3RJbnZpdGF0aW9uXCIsIGFzeW5jIChwKSA9PlxuICAgIGVtaXQoXG4gICAgICBjYXRhbG9nLmludml0YXRpb24udHJhY2tPcmdhbml6YXRpb25NZW1iZXJJbnZpdGVSZWplY3RlZChcbiAgICAgICAgcC5vcmdhbml6YXRpb24sXG4gICAgICAgIHAuaW52aXRhdGlvbixcbiAgICAgICAgcC51c2VyLFxuICAgICAgICBnZXRPcmdhbml6YXRpb25UcmlnZ2VySW5mbyhwLnVzZXIpLFxuICAgICAgKSxcbiAgICApLFxuICApO1xuXG4gIHdyYXBPcmdIb29rPHtcbiAgICBvcmdhbml6YXRpb246IE9yZ2FuaXphdGlvblNuYXBzaG90O1xuICAgIGludml0YXRpb246IEludml0YXRpb25TbmFwc2hvdDtcbiAgICBjYW5jZWxsZWRCeTogVXNlclNuYXBzaG90O1xuICB9Pihob29rcywgXCJhZnRlckNhbmNlbEludml0YXRpb25cIiwgYXN5bmMgKHApID0+XG4gICAgZW1pdChcbiAgICAgIGNhdGFsb2cuaW52aXRhdGlvbi50cmFja09yZ2FuaXphdGlvbk1lbWJlckludml0ZUNhbmNlbGVkKFxuICAgICAgICBwLm9yZ2FuaXphdGlvbixcbiAgICAgICAgcC5pbnZpdGF0aW9uLFxuICAgICAgICBwLmNhbmNlbGxlZEJ5LFxuICAgICAgICBnZXRPcmdhbml6YXRpb25UcmlnZ2VySW5mbyhwLmNhbmNlbGxlZEJ5KSxcbiAgICAgICksXG4gICAgKSxcbiAgKTtcblxuICB3cmFwT3JnSG9vazx7XG4gICAgb3JnYW5pemF0aW9uOiBPcmdhbml6YXRpb25TbmFwc2hvdDtcbiAgICB0ZWFtOiBUZWFtU25hcHNob3Q7XG4gICAgdXNlcjogVXNlclNuYXBzaG90O1xuICB9Pihob29rcywgXCJhZnRlckNyZWF0ZVRlYW1cIiwgYXN5bmMgKHApID0+XG4gICAgZW1pdChcbiAgICAgIGNhdGFsb2cudGVhbS50cmFja09yZ2FuaXphdGlvblRlYW1DcmVhdGVkKFxuICAgICAgICBwLm9yZ2FuaXphdGlvbixcbiAgICAgICAgcC50ZWFtLFxuICAgICAgICBnZXRPcmdhbml6YXRpb25UcmlnZ2VySW5mbyhwLnVzZXIpLFxuICAgICAgKSxcbiAgICApLFxuICApO1xuXG4gIHdyYXBPcmdIb29rPHtcbiAgICBvcmdhbml6YXRpb246IE9yZ2FuaXphdGlvblNuYXBzaG90O1xuICAgIHRlYW0/OiBUZWFtU25hcHNob3Q7XG4gICAgdXNlcjogVXNlclNuYXBzaG90O1xuICB9Pihob29rcywgXCJhZnRlclVwZGF0ZVRlYW1cIiwgYXN5bmMgKHApID0+IHtcbiAgICBpZiAoIXAudGVhbSkgcmV0dXJuO1xuICAgIGF3YWl0IGVtaXQoXG4gICAgICBjYXRhbG9nLnRlYW0udHJhY2tPcmdhbml6YXRpb25UZWFtVXBkYXRlZChcbiAgICAgICAgcC5vcmdhbml6YXRpb24sXG4gICAgICAgIHAudGVhbSxcbiAgICAgICAgZ2V0T3JnYW5pemF0aW9uVHJpZ2dlckluZm8ocC51c2VyKSxcbiAgICAgICksXG4gICAgKTtcbiAgfSk7XG5cbiAgd3JhcE9yZ0hvb2s8e1xuICAgIG9yZ2FuaXphdGlvbjogT3JnYW5pemF0aW9uU25hcHNob3Q7XG4gICAgdGVhbTogVGVhbVNuYXBzaG90O1xuICAgIHVzZXI6IFVzZXJTbmFwc2hvdDtcbiAgfT4oaG9va3MsIFwiYWZ0ZXJEZWxldGVUZWFtXCIsIGFzeW5jIChwKSA9PlxuICAgIGVtaXQoXG4gICAgICBjYXRhbG9nLnRlYW0udHJhY2tPcmdhbml6YXRpb25UZWFtRGVsZXRlZChcbiAgICAgICAgcC5vcmdhbml6YXRpb24sXG4gICAgICAgIHAudGVhbSxcbiAgICAgICAgZ2V0T3JnYW5pemF0aW9uVHJpZ2dlckluZm8ocC51c2VyKSxcbiAgICAgICksXG4gICAgKSxcbiAgKTtcblxuICB3cmFwT3JnSG9vazx7XG4gICAgb3JnYW5pemF0aW9uOiBPcmdhbml6YXRpb25TbmFwc2hvdDtcbiAgICB0ZWFtOiBUZWFtU25hcHNob3Q7XG4gICAgdXNlcjogVXNlclNuYXBzaG90O1xuICAgIHRlYW1NZW1iZXI6IHsgdGVhbUlkOiBzdHJpbmc7IHVzZXJJZDogc3RyaW5nIH07XG4gIH0+KGhvb2tzLCBcImFmdGVyQWRkVGVhbU1lbWJlclwiLCBhc3luYyAocCkgPT5cbiAgICBlbWl0KFxuICAgICAgY2F0YWxvZy50ZWFtLnRyYWNrT3JnYW5pemF0aW9uVGVhbU1lbWJlckFkZGVkKFxuICAgICAgICBwLm9yZ2FuaXphdGlvbixcbiAgICAgICAgcC50ZWFtLFxuICAgICAgICBwLnVzZXIsXG4gICAgICAgIHAudGVhbU1lbWJlcixcbiAgICAgICAgZ2V0T3JnYW5pemF0aW9uVHJpZ2dlckluZm8ocC51c2VyKSxcbiAgICAgICksXG4gICAgKSxcbiAgKTtcblxuICB3cmFwT3JnSG9vazx7XG4gICAgb3JnYW5pemF0aW9uOiBPcmdhbml6YXRpb25TbmFwc2hvdDtcbiAgICB0ZWFtOiBUZWFtU25hcHNob3Q7XG4gICAgdXNlcjogVXNlclNuYXBzaG90O1xuICAgIHRlYW1NZW1iZXI6IHsgdGVhbUlkOiBzdHJpbmc7IHVzZXJJZDogc3RyaW5nIH07XG4gIH0+KGhvb2tzLCBcImFmdGVyUmVtb3ZlVGVhbU1lbWJlclwiLCBhc3luYyAocCkgPT5cbiAgICBlbWl0KFxuICAgICAgY2F0YWxvZy50ZWFtLnRyYWNrT3JnYW5pemF0aW9uVGVhbU1lbWJlclJlbW92ZWQoXG4gICAgICAgIHAub3JnYW5pemF0aW9uLFxuICAgICAgICBwLnRlYW0sXG4gICAgICAgIHAudXNlcixcbiAgICAgICAgcC50ZWFtTWVtYmVyLFxuICAgICAgICBnZXRPcmdhbml6YXRpb25UcmlnZ2VySW5mbyhwLnVzZXIpLFxuICAgICAgKSxcbiAgICApLFxuICApO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztTQUl1QztBQXNCdkMsTUFBTSxjQUFjLFVBQTBCLE1BQU0sTUFBTSxJQUFJLENBQUMsTUFBTTtBQUNyRSxNQUFNLGVBQWUsVUFBMEIsTUFBTSxRQUFRLHVCQUF1QixPQUFPO0FBQzNGLE1BQU0sZ0JBQWdCLFVBQTBCO0NBQzlDLE1BQU0sVUFBVSxZQUFZLFdBQVcsTUFBTSxDQUFDLENBQUMsUUFBUSxlQUFlLFNBQVM7QUFDL0UsUUFBTyxJQUFJLE9BQU8sR0FBRyxRQUFRLFlBQVk7O0FBRTNDLE1BQU0sbUJBQW1CLFdBQStCLFdBQXVDO0FBQzdGLEtBQUksQ0FBQyxVQUFXLFFBQU87Q0FDdkIsTUFBTSxZQUFZLFdBQVcsVUFBVTtBQUN2QyxRQUFPLE9BQU8s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
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type Knex } from "knex";
|
|
2
|
-
import { type AuditLogEvent } from "./audit-log
|
|
2
|
+
import { type AuditLogEvent } from "./audit-log/events";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* sonamuAuditLog 플러그인이 구성한 AuditLogEvent를 audit_events 테이블에 적재합니다.
|
|
5
5
|
* ON CONFLICT (dedupe_key) DO NOTHING으로 중복을 silent 무시합니다.
|
|
6
|
-
* auth.
|
|
6
|
+
* auth.plugins에 sonamuAuditLog() 추가 시 sonamu 내부에서 자동으로 호출됩니다.
|
|
7
7
|
*/
|
|
8
8
|
export declare function ingestAuditEvent(db: Knex, event: AuditLogEvent): Promise<void>;
|
|
9
9
|
//# sourceMappingURL=audit-log-ingestor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-log-ingestor.d.ts","sourceRoot":"","sources":["../../src/auth/audit-log-ingestor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"audit-log-ingestor.d.ts","sourceRoot":"","sources":["../../src/auth/audit-log-ingestor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAuIxD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFpF"}
|