@dreadkn1ght123/auth-express 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -0
- package/dist/index.d.ts +165 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +883 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# @dreadkn1ght123/auth-express
|
|
2
|
+
|
|
3
|
+
Express adapter for `@dreadkn1ght123/auth-core`. Mount `auth.router`, then mount
|
|
4
|
+
`auth.authenticate` before protected application routes. Authorization behavior
|
|
5
|
+
is explicit: pass `{ mode: "html" }` for login redirects or `{ mode: "api" }`
|
|
6
|
+
for JSON 401/403 responses.
|
|
7
|
+
|
|
8
|
+
The logger retains stable event names, including `vvp.auth.login.started`,
|
|
9
|
+
`vvp.auth.callback.succeeded`, `vvp.auth.callback.rejected`,
|
|
10
|
+
`vvp.auth.logout.succeeded`, `vvp.auth.logout.rejected`,
|
|
11
|
+
`vvp.auth.session.refresh_failed`, and `vvp.auth.access.denied`. Rejections add
|
|
12
|
+
stable `stage`, `reason`, error/cause codes, and correlation ID where known.
|
|
13
|
+
Startup emits `vvp.auth.ready` only after configuration, discovery, and
|
|
14
|
+
store checks succeed. Unexpected adapter errors use `vvp.auth.internal_error`.
|
|
15
|
+
These events are diagnostic metadata, never an audit record of provider logout
|
|
16
|
+
completion.
|
|
17
|
+
|
|
18
|
+
Production requires shared implementations of `SessionStore` and
|
|
19
|
+
`AuthTransactionStore`; transaction `consume` must be atomic.
|
|
20
|
+
`MemorySessionStore` and `MemoryAuthTransactionStore` are process-local
|
|
21
|
+
development/test utilities and are rejected by this adapter in production.
|
|
22
|
+
|
|
23
|
+
`AuthTransactionStore.consume(id, expectedState)` must compare the expected
|
|
24
|
+
state and atomically return `{ outcome: "consumed", transaction }` or a safe
|
|
25
|
+
failure outcome while deleting only a matching, unexpired record. A mismatch
|
|
26
|
+
must not consume a valid transaction. Distributed stores may return
|
|
27
|
+
`ambiguous` when they cannot safely distinguish a missing record from an
|
|
28
|
+
already-consumed record; never infer or log transaction IDs or state values.
|
|
29
|
+
|
|
30
|
+
## SDK-owned browser flow
|
|
31
|
+
|
|
32
|
+
The adapter owns the complete single-provider UX. Applications must not render
|
|
33
|
+
an SSO chooser, local login form, callback error page, or logout landing page.
|
|
34
|
+
|
|
35
|
+
| Default route | Method | Purpose |
|
|
36
|
+
|---|---:|---|
|
|
37
|
+
| `/auth/start` | GET | Safe normal entry; preserves validated `returnTo` and provides iframe fallback |
|
|
38
|
+
| `/auth/login` | GET | Internal transaction creation and redirect to IAM; retained for compatibility |
|
|
39
|
+
| `/auth/callback` | GET | Validates callback, creates session, then returns or redirects to SDK error UI |
|
|
40
|
+
| `/auth/logout` | POST | Deletes local session and starts provider logout |
|
|
41
|
+
| `/auth/signed-out` | GET | Non-automatic signed-out page with explicit “sign in again” action |
|
|
42
|
+
| `/auth/error` | GET | Allowlisted safe error and retry page |
|
|
43
|
+
| `/auth/me` | GET | Token-free public session or 401 |
|
|
44
|
+
|
|
45
|
+
`requireAuth({ mode: "html" })` sends an unauthenticated browser to
|
|
46
|
+
`/auth/start`, not directly to `/auth/login`. `/auth/login` remains the internal
|
|
47
|
+
transaction endpoint; consumers must not hardcode it as their normal entry.
|
|
48
|
+
API mode still returns JSON 401/403.
|
|
49
|
+
|
|
50
|
+
Override routes centrally when needed:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const auth = await createVvpAuth({
|
|
54
|
+
config,
|
|
55
|
+
sessionStore,
|
|
56
|
+
transactionStore,
|
|
57
|
+
routes: {
|
|
58
|
+
basePath: "/identity",
|
|
59
|
+
start: "start",
|
|
60
|
+
login: "login",
|
|
61
|
+
callback: "complete",
|
|
62
|
+
logout: "logout",
|
|
63
|
+
signedOut: "signed-out",
|
|
64
|
+
error: "error",
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Production `config.publicOrigin` derives exact callback and post-logout
|
|
70
|
+
redirects from these routes. Register both resulting URIs in Keycloak. The
|
|
71
|
+
transaction-cookie path follows `basePath`; an explicit cookie path must
|
|
72
|
+
contain login and callback routes or startup fails with `CONFIG_INVALID`.
|
|
73
|
+
|
|
74
|
+
For server-rendered navigation use `auth.createLoginUrl(returnTo)` or
|
|
75
|
+
`auth.createLoginLink(returnTo)`: both target the SDK start route.
|
|
76
|
+
`createLoginLink` supplies `target: "_top"` and safe `rel`. Login must be a
|
|
77
|
+
browser navigation, never `fetch`/XHR. Invalid external `returnTo` values are
|
|
78
|
+
rejected or normalized by SDK policy; never concatenate one manually.
|
|
79
|
+
|
|
80
|
+
Instance role helpers use configured `clientId`, avoiding a stale hardcoded ID
|
|
81
|
+
after a rename. Prefer `auth.hasClientRole(actor, role)` and
|
|
82
|
+
`auth.requireClientRole(role, behavior)` without `behavior.clientId`;
|
|
83
|
+
module-level helpers and the optional `clientId` behavior field remain
|
|
84
|
+
available for intentional cross-client policies.
|
|
85
|
+
|
|
86
|
+
SDK pages are Russian by default with English locale support, responsive,
|
|
87
|
+
keyboard accessible, independent of app CSS/JavaScript, and protected by a
|
|
88
|
+
strict CSP. Optional `ui` branding (`productName`, local `logoUrl`,
|
|
89
|
+
`supportText`, allowlisted text overrides) is escaped and must contain no HTML
|
|
90
|
+
or remote script dependency. Error pages accept only public allowlisted reasons,
|
|
91
|
+
contain a safe retry to `/auth/start` and optional correlation ID, and never
|
|
92
|
+
expose provider/exception text. The signed-out page never automatically starts
|
|
93
|
+
SSO, preventing an immediate logout/login loop.
|
|
94
|
+
|
|
95
|
+
Public error reasons are limited to `transaction_missing`,
|
|
96
|
+
`transaction_expired`, `transaction_already_used`, `provider_denied`,
|
|
97
|
+
`token_validation_failed`, `provider_unavailable`, `session_failed`,
|
|
98
|
+
`configuration_error`, and `unknown`. They select user text only; detailed
|
|
99
|
+
callback stage/reason remains in safe structured logs and is never copied into
|
|
100
|
+
the browser URL.
|
|
101
|
+
See the workspace [`UPGRADE.md`](../../UPGRADE.md) and
|
|
102
|
+
[`docs/sdk-usage.md`](../../docs/sdk-usage.md) for the `0.2.0` migration.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { type AuthorizationOptions, type AuthConfig, type AuthConfigInput, type AuthLogger, type AuthStoreCapabilities, type Actor, type ServerSession, type SessionStore, type RuntimeEnvironment, type TransactionConsumeOutcome } from "@dreadkn1ght123/auth-core";
|
|
2
|
+
import { Router, type Request, type RequestHandler } from "express";
|
|
3
|
+
declare global {
|
|
4
|
+
namespace Express {
|
|
5
|
+
interface Request {
|
|
6
|
+
vvpActor?: Actor;
|
|
7
|
+
vvpCorrelationId?: string;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export declare const AUTH_EXPRESS_EVENTS: {
|
|
12
|
+
readonly ready: "vvp.auth.ready";
|
|
13
|
+
readonly loginStarted: "vvp.auth.login.started";
|
|
14
|
+
readonly callbackSucceeded: "vvp.auth.callback.succeeded";
|
|
15
|
+
readonly callbackRejected: "vvp.auth.callback.rejected";
|
|
16
|
+
readonly logoutSucceeded: "vvp.auth.logout.succeeded";
|
|
17
|
+
readonly logoutRejected: "vvp.auth.logout.rejected";
|
|
18
|
+
readonly logoutLocalSessionDeleted: "vvp.auth.logout.local_session_deleted";
|
|
19
|
+
readonly logoutRedirectCreated: "vvp.auth.logout.redirect_created";
|
|
20
|
+
readonly logoutProviderRejected: "vvp.auth.logout.provider_rejected";
|
|
21
|
+
readonly logoutInvalidRedirect: "vvp.auth.logout.invalid_redirect";
|
|
22
|
+
readonly sessionRefreshFailed: "vvp.auth.session.refresh_failed";
|
|
23
|
+
readonly accessDenied: "vvp.auth.access.denied";
|
|
24
|
+
readonly internalError: "vvp.auth.internal_error";
|
|
25
|
+
};
|
|
26
|
+
export interface AuthTransaction {
|
|
27
|
+
id: string;
|
|
28
|
+
state: string;
|
|
29
|
+
nonce: string;
|
|
30
|
+
codeVerifier: string;
|
|
31
|
+
returnTo: string;
|
|
32
|
+
expiresAt: number;
|
|
33
|
+
}
|
|
34
|
+
export type AuthTransactionConsumeOutcome = TransactionConsumeOutcome<AuthTransaction>;
|
|
35
|
+
/** This operation must be implemented as one atomic compare-and-delete. */
|
|
36
|
+
export interface AuthTransactionStore {
|
|
37
|
+
readonly capabilities?: AuthStoreCapabilities;
|
|
38
|
+
set(transaction: AuthTransaction, ttlSeconds: number): Promise<void>;
|
|
39
|
+
consume(id: string, expectedState: string): Promise<AuthTransactionConsumeOutcome>;
|
|
40
|
+
}
|
|
41
|
+
export declare class MemoryAuthTransactionStore implements AuthTransactionStore {
|
|
42
|
+
#private;
|
|
43
|
+
constructor(environment: RuntimeEnvironment, options?: {
|
|
44
|
+
now?: () => number;
|
|
45
|
+
});
|
|
46
|
+
set(transaction: AuthTransaction, ttlSeconds: number): Promise<void>;
|
|
47
|
+
consume(id: string, expectedState: string): Promise<AuthTransactionConsumeOutcome>;
|
|
48
|
+
}
|
|
49
|
+
export interface VvpOidcOperations {
|
|
50
|
+
createAuthorizationRequest(options?: AuthorizationOptions): Promise<{
|
|
51
|
+
authorizationUrl: URL;
|
|
52
|
+
state: string;
|
|
53
|
+
nonce: string;
|
|
54
|
+
codeVerifier: string;
|
|
55
|
+
correlationId?: string;
|
|
56
|
+
}>;
|
|
57
|
+
handleCallback(input: {
|
|
58
|
+
callbackUrl: URL;
|
|
59
|
+
state: string;
|
|
60
|
+
nonce: string;
|
|
61
|
+
codeVerifier: string;
|
|
62
|
+
}): Promise<ServerSession>;
|
|
63
|
+
refreshSession(sessionId: string): Promise<ServerSession>;
|
|
64
|
+
logout(sessionId: string): Promise<URL>;
|
|
65
|
+
}
|
|
66
|
+
export interface AccessBehavior {
|
|
67
|
+
/** html redirects unauthenticated users; api returns JSON 401/403. */
|
|
68
|
+
mode: "html" | "api";
|
|
69
|
+
}
|
|
70
|
+
export interface CreateVvpAuthOptions {
|
|
71
|
+
config: AuthConfigInput;
|
|
72
|
+
sessionStore?: SessionStore;
|
|
73
|
+
transactionStore?: AuthTransactionStore;
|
|
74
|
+
logger?: AuthLogger;
|
|
75
|
+
oidcClient?: VvpOidcOperations;
|
|
76
|
+
cookieName?: string;
|
|
77
|
+
transactionCookieName?: string;
|
|
78
|
+
transactionTtlSeconds?: number;
|
|
79
|
+
refreshBeforeExpirySeconds?: number;
|
|
80
|
+
routes?: AuthRouteOptions;
|
|
81
|
+
/** Safe, optional branding for the SDK-owned browser pages. */
|
|
82
|
+
ui?: AuthUiOptions;
|
|
83
|
+
/** Path for the session cookie. Defaults to /. */
|
|
84
|
+
cookiePath?: string;
|
|
85
|
+
/** Path for the short-lived transaction cookie. Defaults to basePath. */
|
|
86
|
+
transactionCookiePath?: string;
|
|
87
|
+
now?: () => number;
|
|
88
|
+
}
|
|
89
|
+
export interface AuthRouteOptions {
|
|
90
|
+
basePath?: string;
|
|
91
|
+
start?: string;
|
|
92
|
+
login?: string;
|
|
93
|
+
callback?: string;
|
|
94
|
+
logout?: string;
|
|
95
|
+
session?: string;
|
|
96
|
+
signedOut?: string;
|
|
97
|
+
error?: string;
|
|
98
|
+
/** Names accepted by AuthConfigInput.routes; preferred for new integrations. */
|
|
99
|
+
startPath?: string;
|
|
100
|
+
loginPath?: string;
|
|
101
|
+
callbackPath?: string;
|
|
102
|
+
logoutPath?: string;
|
|
103
|
+
sessionPath?: string;
|
|
104
|
+
signedOutPath?: string;
|
|
105
|
+
errorPath?: string;
|
|
106
|
+
cookiePath?: string;
|
|
107
|
+
}
|
|
108
|
+
export interface NormalizedAuthRoutes {
|
|
109
|
+
basePath: string;
|
|
110
|
+
start: string;
|
|
111
|
+
login: string;
|
|
112
|
+
callback: string;
|
|
113
|
+
logout: string;
|
|
114
|
+
session: string;
|
|
115
|
+
signedOut: string;
|
|
116
|
+
error: string;
|
|
117
|
+
}
|
|
118
|
+
export interface AuthUiOptions {
|
|
119
|
+
locale?: "ru" | "en";
|
|
120
|
+
productName?: string;
|
|
121
|
+
logoUrl?: string;
|
|
122
|
+
supportText?: string;
|
|
123
|
+
text?: Partial<{
|
|
124
|
+
continueLogin: string;
|
|
125
|
+
startTitle: string;
|
|
126
|
+
startBody: string;
|
|
127
|
+
signedOutTitle: string;
|
|
128
|
+
signedOutBody: string;
|
|
129
|
+
signInAgain: string;
|
|
130
|
+
errorTitle: string;
|
|
131
|
+
tryAgain: string;
|
|
132
|
+
reference: string;
|
|
133
|
+
}>;
|
|
134
|
+
}
|
|
135
|
+
export interface BrowserLoginLink {
|
|
136
|
+
href: string;
|
|
137
|
+
/** Always escapes a containing iframe during browser navigation. */
|
|
138
|
+
target: "_top";
|
|
139
|
+
rel: "noopener noreferrer";
|
|
140
|
+
}
|
|
141
|
+
export interface VvpAuth {
|
|
142
|
+
config: AuthConfig;
|
|
143
|
+
router: Router;
|
|
144
|
+
authenticate: RequestHandler;
|
|
145
|
+
requireAuth(options: AccessBehavior): RequestHandler;
|
|
146
|
+
requireRealmRole(role: string, options: AccessBehavior): RequestHandler[];
|
|
147
|
+
requireClientRole(role: string, options: AccessBehavior & {
|
|
148
|
+
clientId?: string;
|
|
149
|
+
}): RequestHandler[];
|
|
150
|
+
requireAnyClientRole(roles: readonly string[], options: AccessBehavior & {
|
|
151
|
+
clientId?: string;
|
|
152
|
+
}): RequestHandler[];
|
|
153
|
+
createLoginUrl(returnTo?: string): string;
|
|
154
|
+
createLoginLink(returnTo?: string): BrowserLoginLink;
|
|
155
|
+
hasClientRole(actor: Actor | undefined, role: string): boolean;
|
|
156
|
+
hasAnyClientRole(actor: Actor | undefined, roles: readonly string[]): boolean;
|
|
157
|
+
routes: NormalizedAuthRoutes;
|
|
158
|
+
}
|
|
159
|
+
export declare function getActor(req: Request): Actor | undefined;
|
|
160
|
+
export declare function isAuthenticated(req: Request): boolean;
|
|
161
|
+
export declare function hasRealmRole(actor: Actor | undefined, role: string): boolean;
|
|
162
|
+
export declare function hasClientRole(actor: Actor | undefined, role: string, clientId: string): boolean;
|
|
163
|
+
export declare function hasAnyClientRole(actor: Actor | undefined, roles: readonly string[], clientId: string): boolean;
|
|
164
|
+
export declare function createVvpAuth(options: CreateVvpAuthOptions): Promise<VvpAuth>;
|
|
165
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,883 @@
|
|
|
1
|
+
import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { MemorySessionStore, AuthError, classifyAuthError, VvpOidcClient, safeReturnTo, toPublicSession, validateConfig, assertProductionSafeStore, transactionConsumeError, } from "@dreadkn1ght123/auth-core";
|
|
3
|
+
import { Router, } from "express";
|
|
4
|
+
export const AUTH_EXPRESS_EVENTS = {
|
|
5
|
+
ready: "vvp.auth.ready",
|
|
6
|
+
loginStarted: "vvp.auth.login.started",
|
|
7
|
+
callbackSucceeded: "vvp.auth.callback.succeeded",
|
|
8
|
+
callbackRejected: "vvp.auth.callback.rejected",
|
|
9
|
+
logoutSucceeded: "vvp.auth.logout.succeeded",
|
|
10
|
+
logoutRejected: "vvp.auth.logout.rejected",
|
|
11
|
+
logoutLocalSessionDeleted: "vvp.auth.logout.local_session_deleted",
|
|
12
|
+
logoutRedirectCreated: "vvp.auth.logout.redirect_created",
|
|
13
|
+
logoutProviderRejected: "vvp.auth.logout.provider_rejected",
|
|
14
|
+
logoutInvalidRedirect: "vvp.auth.logout.invalid_redirect",
|
|
15
|
+
sessionRefreshFailed: "vvp.auth.session.refresh_failed",
|
|
16
|
+
accessDenied: "vvp.auth.access.denied",
|
|
17
|
+
internalError: "vvp.auth.internal_error",
|
|
18
|
+
};
|
|
19
|
+
export class MemoryAuthTransactionStore {
|
|
20
|
+
#entries = new Map();
|
|
21
|
+
#consumed = new Map();
|
|
22
|
+
#now;
|
|
23
|
+
constructor(environment, options = {}) {
|
|
24
|
+
if (environment === "production") {
|
|
25
|
+
throw new AuthError("SESSION_STORE_UNSAFE", "MemoryAuthTransactionStore must not be used in production");
|
|
26
|
+
}
|
|
27
|
+
this.#now = options.now ?? Date.now;
|
|
28
|
+
}
|
|
29
|
+
async set(transaction, ttlSeconds) {
|
|
30
|
+
this.#entries.set(transaction.id, {
|
|
31
|
+
...structuredClone(transaction),
|
|
32
|
+
expiresAt: Math.min(transaction.expiresAt, this.#now() + ttlSeconds * 1_000),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async consume(id, expectedState) {
|
|
36
|
+
for (const [consumedId, expiresAt] of this.#consumed) {
|
|
37
|
+
if (expiresAt <= this.#now())
|
|
38
|
+
this.#consumed.delete(consumedId);
|
|
39
|
+
}
|
|
40
|
+
const transaction = this.#entries.get(id);
|
|
41
|
+
if (!transaction) {
|
|
42
|
+
return {
|
|
43
|
+
status: this.#consumed.has(id) ? "already_consumed" : "not_found",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (transaction.expiresAt <= this.#now()) {
|
|
47
|
+
this.#entries.delete(id);
|
|
48
|
+
return { status: "expired" };
|
|
49
|
+
}
|
|
50
|
+
if (!constantTimeEqual(transaction.state, expectedState)) {
|
|
51
|
+
return { status: "state_mismatch" };
|
|
52
|
+
}
|
|
53
|
+
this.#entries.delete(id);
|
|
54
|
+
this.#consumed.set(id, transaction.expiresAt);
|
|
55
|
+
return { status: "ok", transaction: structuredClone(transaction) };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const NOOP_LOGGER = {
|
|
59
|
+
debug() { },
|
|
60
|
+
info() { },
|
|
61
|
+
warn() { },
|
|
62
|
+
error() { },
|
|
63
|
+
};
|
|
64
|
+
const ID_PATTERN = /^[A-Za-z0-9_-]{32,128}$/;
|
|
65
|
+
const CORRELATION_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
66
|
+
function escapeHtml(value) {
|
|
67
|
+
return value.replace(/[&<>"']/g, (character) => ({
|
|
68
|
+
"&": "&",
|
|
69
|
+
"<": "<",
|
|
70
|
+
">": ">",
|
|
71
|
+
'"': """,
|
|
72
|
+
"'": "'",
|
|
73
|
+
})[character]);
|
|
74
|
+
}
|
|
75
|
+
const PUBLIC_ERROR_REASONS = new Set([
|
|
76
|
+
"transaction_missing", "transaction_expired", "transaction_already_used",
|
|
77
|
+
"provider_denied", "token_validation_failed", "provider_unavailable",
|
|
78
|
+
"session_failed", "configuration_error", "unknown",
|
|
79
|
+
]);
|
|
80
|
+
const ERROR_MESSAGES = {
|
|
81
|
+
ru: {
|
|
82
|
+
transaction_missing: "Не удалось найти попытку входа. Начните авторизацию заново.",
|
|
83
|
+
transaction_expired: "Время попытки входа истекло. Начните авторизацию заново.",
|
|
84
|
+
transaction_already_used: "Эта ссылка входа уже была использована. Начните новую авторизацию.",
|
|
85
|
+
provider_denied: "Вход был отменён или отклонён системой авторизации.",
|
|
86
|
+
token_validation_failed: "Не удалось проверить данные авторизации. Обратитесь к администратору.",
|
|
87
|
+
provider_unavailable: "Система авторизации временно недоступна. Попробуйте позже.",
|
|
88
|
+
session_failed: "Не удалось создать сеанс приложения. Попробуйте снова.",
|
|
89
|
+
configuration_error: "Сервис входа настроен неверно. Обратитесь к администратору.",
|
|
90
|
+
unknown: "Не удалось завершить вход.",
|
|
91
|
+
},
|
|
92
|
+
en: {
|
|
93
|
+
transaction_missing: "The sign-in attempt could not be found. Start again.",
|
|
94
|
+
transaction_expired: "The sign-in attempt expired. Start again.",
|
|
95
|
+
transaction_already_used: "This sign-in link was already used. Start a new sign-in.",
|
|
96
|
+
provider_denied: "Sign-in was cancelled or denied by the identity provider.",
|
|
97
|
+
token_validation_failed: "The sign-in data could not be verified. Contact an administrator.",
|
|
98
|
+
provider_unavailable: "The identity provider is temporarily unavailable. Try again later.",
|
|
99
|
+
session_failed: "The application session could not be created. Try again.",
|
|
100
|
+
configuration_error: "The sign-in service is misconfigured. Contact an administrator.",
|
|
101
|
+
unknown: "Sign-in could not be completed.",
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
function validateUi(options) {
|
|
105
|
+
const locale = options?.locale ?? "ru";
|
|
106
|
+
const defaults = locale === "en" ? {
|
|
107
|
+
continueLogin: "Continue sign-in", startTitle: "Sign in",
|
|
108
|
+
startBody: "Continue to the corporate sign-in service.",
|
|
109
|
+
signedOutTitle: "You have signed out", signedOutBody: "Your session has ended.",
|
|
110
|
+
signInAgain: "Sign in again", errorTitle: "Sign-in error",
|
|
111
|
+
tryAgain: "Try again", reference: "Reference",
|
|
112
|
+
} : {
|
|
113
|
+
continueLogin: "Продолжить вход", startTitle: "Вход в систему",
|
|
114
|
+
startBody: "Продолжите вход через корпоративную систему авторизации.",
|
|
115
|
+
signedOutTitle: "Вы вышли из системы", signedOutBody: "Сеанс работы завершён.",
|
|
116
|
+
signInAgain: "Войти снова", errorTitle: "Ошибка входа",
|
|
117
|
+
tryAgain: "Попробовать снова", reference: "Код обращения",
|
|
118
|
+
};
|
|
119
|
+
let logoUrl;
|
|
120
|
+
if (options?.logoUrl !== undefined) {
|
|
121
|
+
try {
|
|
122
|
+
const parsed = new URL(options.logoUrl, "https://sdk.invalid");
|
|
123
|
+
if (parsed.origin !== "https://sdk.invalid" || !options.logoUrl.startsWith("/") ||
|
|
124
|
+
options.logoUrl.startsWith("//") || parsed.username || parsed.password ||
|
|
125
|
+
parsed.search || parsed.hash)
|
|
126
|
+
throw new Error();
|
|
127
|
+
logoUrl = parsed.pathname;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
throw new AuthError("CONFIG_INVALID", "ui.logoUrl must be a local absolute URL without query or fragment");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
locale,
|
|
135
|
+
productName: options?.productName ?? "VVP",
|
|
136
|
+
supportText: options?.supportText ?? "",
|
|
137
|
+
text: { ...defaults, ...options?.text },
|
|
138
|
+
...(logoUrl ? { logoUrl } : {}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function page(input) {
|
|
142
|
+
const { ui } = input;
|
|
143
|
+
const logo = ui.logoUrl
|
|
144
|
+
? `<img class="logo" src="${escapeHtml(ui.logoUrl)}" alt="">`
|
|
145
|
+
: "";
|
|
146
|
+
const support = ui.supportText
|
|
147
|
+
? `<p class="support">${escapeHtml(ui.supportText)}</p>`
|
|
148
|
+
: "";
|
|
149
|
+
const reference = input.correlationId
|
|
150
|
+
? `<p class="reference"><small>${escapeHtml(ui.text.reference)}: <code>${escapeHtml(input.correlationId)}</code></small></p>`
|
|
151
|
+
: "";
|
|
152
|
+
const script = input.autoNavigate
|
|
153
|
+
? `<script nonce="${input.nonce}">try{window.top.location.assign(${JSON.stringify(input.actionHref).replace(/</g, "\\u003c")})}catch(e){}</script>`
|
|
154
|
+
: "";
|
|
155
|
+
return `<!doctype html>
|
|
156
|
+
<html lang="${ui.locale}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
157
|
+
<title>${escapeHtml(input.title)}</title><style nonce="${input.nonce}">
|
|
158
|
+
*{box-sizing:border-box}body{margin:0;background:#f5f6f8;color:#17202a;font:16px/1.5 system-ui,-apple-system,sans-serif}
|
|
159
|
+
main{width:min(92%,32rem);margin:12vh auto;background:#fff;border:1px solid #dfe3e8;border-radius:12px;padding:2rem;box-shadow:0 8px 28px #17202a12}
|
|
160
|
+
.brand{display:flex;align-items:center;gap:.75rem;font-weight:700}.logo{max-width:8rem;max-height:3rem}h1{font-size:1.6rem;margin:1.5rem 0 .5rem}
|
|
161
|
+
.button{display:inline-block;margin-top:1rem;padding:.7rem 1rem;border-radius:6px;background:#175cd3;color:#fff;text-decoration:none;font-weight:650}
|
|
162
|
+
.button:focus{outline:3px solid #84adff;outline-offset:3px}.support,.reference{color:#59636e;margin-top:1.25rem}code{overflow-wrap:anywhere}
|
|
163
|
+
</style></head><body><main>
|
|
164
|
+
<div class="brand">${logo}<span>${escapeHtml(ui.productName)}</span></div>
|
|
165
|
+
<h1 tabindex="-1">${escapeHtml(input.title)}</h1><p>${escapeHtml(input.body)}</p>
|
|
166
|
+
<a class="button" href="${escapeHtml(input.actionHref)}" target="_top" rel="noopener noreferrer">${escapeHtml(input.actionText)}</a>
|
|
167
|
+
${support}${reference}</main>${script}</body></html>`;
|
|
168
|
+
}
|
|
169
|
+
function opaqueId() {
|
|
170
|
+
return randomBytes(32).toString("base64url");
|
|
171
|
+
}
|
|
172
|
+
function parseCookies(header) {
|
|
173
|
+
const result = {};
|
|
174
|
+
for (const item of header?.split(";") ?? []) {
|
|
175
|
+
const separator = item.indexOf("=");
|
|
176
|
+
if (separator < 1)
|
|
177
|
+
continue;
|
|
178
|
+
const name = item.slice(0, separator).trim();
|
|
179
|
+
try {
|
|
180
|
+
result[name] = decodeURIComponent(item.slice(separator + 1).trim());
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Malformed cookies are ignored.
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
function constantTimeEqual(left, right) {
|
|
189
|
+
const a = Buffer.from(left);
|
|
190
|
+
const b = Buffer.from(right);
|
|
191
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
192
|
+
}
|
|
193
|
+
function normalizePath(value, field) {
|
|
194
|
+
if (!value.startsWith("/") || value.includes("?") || value.includes("#") ||
|
|
195
|
+
value.includes("\\") || value.includes("//")) {
|
|
196
|
+
throw new AuthError("CONFIG_INVALID", `${field} must be a normalized absolute path`);
|
|
197
|
+
}
|
|
198
|
+
const normalized = value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
199
|
+
if (normalized.split("/").some((segment) => segment === "." || segment === "..")) {
|
|
200
|
+
throw new AuthError("CONFIG_INVALID", `${field} must not contain dot segments`);
|
|
201
|
+
}
|
|
202
|
+
return normalized;
|
|
203
|
+
}
|
|
204
|
+
function joinRoute(basePath, route, fallback) {
|
|
205
|
+
const value = route ?? fallback;
|
|
206
|
+
return normalizePath(value.startsWith("/") ? value : `${basePath}/${value}`, "auth route");
|
|
207
|
+
}
|
|
208
|
+
function normalizeRoutes(input = {}) {
|
|
209
|
+
const basePath = normalizePath(input.basePath ?? "/auth", "routes.basePath");
|
|
210
|
+
const routes = {
|
|
211
|
+
basePath,
|
|
212
|
+
start: joinRoute(basePath, input.startPath ?? input.start, "start"),
|
|
213
|
+
login: joinRoute(basePath, input.loginPath ?? input.login, "login"),
|
|
214
|
+
callback: joinRoute(basePath, input.callbackPath ?? input.callback, "callback"),
|
|
215
|
+
logout: joinRoute(basePath, input.logoutPath ?? input.logout, "logout"),
|
|
216
|
+
session: joinRoute(basePath, input.sessionPath ?? input.session, "me"),
|
|
217
|
+
signedOut: joinRoute(basePath, input.signedOutPath ?? input.signedOut, "signed-out"),
|
|
218
|
+
error: joinRoute(basePath, input.errorPath ?? input.error, "error"),
|
|
219
|
+
};
|
|
220
|
+
const paths = [
|
|
221
|
+
routes.start, routes.login, routes.callback, routes.logout, routes.session,
|
|
222
|
+
routes.signedOut, routes.error,
|
|
223
|
+
];
|
|
224
|
+
if (new Set(paths).size !== paths.length) {
|
|
225
|
+
throw new AuthError("CONFIG_INVALID", "Authentication routes must be unique");
|
|
226
|
+
}
|
|
227
|
+
return routes;
|
|
228
|
+
}
|
|
229
|
+
function pathContains(cookiePath, requestPath) {
|
|
230
|
+
return cookiePath === "/" || requestPath === cookiePath ||
|
|
231
|
+
requestPath.startsWith(`${cookiePath}/`);
|
|
232
|
+
}
|
|
233
|
+
function requestLanguage(req) {
|
|
234
|
+
const header = req.get("accept-language")?.trim().toLowerCase();
|
|
235
|
+
return header?.startsWith("en") ? "en" : "ru";
|
|
236
|
+
}
|
|
237
|
+
function publicCallbackReason(error) {
|
|
238
|
+
const diagnostic = classifyAuthError(error);
|
|
239
|
+
const value = `${error instanceof AuthError ? error.code : ""} ${diagnostic.reason}`.toLowerCase();
|
|
240
|
+
if (value.includes("denied") || value.includes("access_denied") || value.includes("cancel")) {
|
|
241
|
+
return "provider_denied";
|
|
242
|
+
}
|
|
243
|
+
if (value.includes("config") || value.includes("invalid_client")) {
|
|
244
|
+
return "configuration_error";
|
|
245
|
+
}
|
|
246
|
+
if (value.includes("token") || value.includes("nonce") || value.includes("issuer") ||
|
|
247
|
+
value.includes("audience") || value.includes("signature") || value.includes("claim") ||
|
|
248
|
+
value.includes("subject") || value.includes("azp")) {
|
|
249
|
+
return "token_validation_failed";
|
|
250
|
+
}
|
|
251
|
+
if (value.includes("unavailable") || value.includes("network") ||
|
|
252
|
+
value.includes("timeout") || value.includes("endpoint")) {
|
|
253
|
+
return "provider_unavailable";
|
|
254
|
+
}
|
|
255
|
+
if (value.includes("session") || value.includes("store"))
|
|
256
|
+
return "session_failed";
|
|
257
|
+
return "unknown";
|
|
258
|
+
}
|
|
259
|
+
function asyncHandler(handler) {
|
|
260
|
+
return (req, res, next) => void handler(req, res, next).catch(next);
|
|
261
|
+
}
|
|
262
|
+
export function getActor(req) {
|
|
263
|
+
return req.vvpActor;
|
|
264
|
+
}
|
|
265
|
+
export function isAuthenticated(req) {
|
|
266
|
+
return Boolean(req.vvpActor);
|
|
267
|
+
}
|
|
268
|
+
export function hasRealmRole(actor, role) {
|
|
269
|
+
return actor?.realmRoles.includes(role.toLowerCase()) ?? false;
|
|
270
|
+
}
|
|
271
|
+
export function hasClientRole(actor, role, clientId) {
|
|
272
|
+
return actor?.clientRoles[clientId]?.includes(role.toLowerCase()) ?? false;
|
|
273
|
+
}
|
|
274
|
+
export function hasAnyClientRole(actor, roles, clientId) {
|
|
275
|
+
return roles.some((role) => hasClientRole(actor, role, clientId));
|
|
276
|
+
}
|
|
277
|
+
export async function createVvpAuth(options) {
|
|
278
|
+
// `routes` was originally documented as an Express option. Normalize that
|
|
279
|
+
// shape into the core contract before validation so production receives the
|
|
280
|
+
// same callback/cookie checks as every other configuration source.
|
|
281
|
+
const legacyRoutes = options.routes;
|
|
282
|
+
const configInput = legacyRoutes
|
|
283
|
+
? {
|
|
284
|
+
...options.config,
|
|
285
|
+
routes: {
|
|
286
|
+
...options.config.routes,
|
|
287
|
+
...(legacyRoutes.basePath !== undefined
|
|
288
|
+
? { basePath: legacyRoutes.basePath } : {}),
|
|
289
|
+
...(legacyRoutes.startPath ?? legacyRoutes.start
|
|
290
|
+
? { startPath: legacyRoutes.startPath ?? legacyRoutes.start } : {}),
|
|
291
|
+
...(legacyRoutes.loginPath ?? legacyRoutes.login
|
|
292
|
+
? { loginPath: legacyRoutes.loginPath ?? legacyRoutes.login } : {}),
|
|
293
|
+
...(legacyRoutes.callbackPath ?? legacyRoutes.callback
|
|
294
|
+
? { callbackPath: legacyRoutes.callbackPath ?? legacyRoutes.callback } : {}),
|
|
295
|
+
...(legacyRoutes.logoutPath ?? legacyRoutes.logout
|
|
296
|
+
? { logoutPath: legacyRoutes.logoutPath ?? legacyRoutes.logout } : {}),
|
|
297
|
+
...(legacyRoutes.sessionPath ?? legacyRoutes.session
|
|
298
|
+
? { sessionPath: legacyRoutes.sessionPath ?? legacyRoutes.session } : {}),
|
|
299
|
+
...(legacyRoutes.signedOutPath ?? legacyRoutes.signedOut
|
|
300
|
+
? {
|
|
301
|
+
signedOutPath: legacyRoutes.signedOutPath ?? legacyRoutes.signedOut,
|
|
302
|
+
} : {}),
|
|
303
|
+
...(legacyRoutes.errorPath ?? legacyRoutes.error
|
|
304
|
+
? { errorPath: legacyRoutes.errorPath ?? legacyRoutes.error } : {}),
|
|
305
|
+
...(legacyRoutes.cookiePath !== undefined
|
|
306
|
+
? { cookiePath: legacyRoutes.cookiePath } : {}),
|
|
307
|
+
},
|
|
308
|
+
}
|
|
309
|
+
: options.config;
|
|
310
|
+
const config = validateConfig(configInput);
|
|
311
|
+
const returnToOptions = {
|
|
312
|
+
baseOrigin: config.publicOrigin?.origin ?? config.redirectUri.origin,
|
|
313
|
+
allowedOrigins: config.allowedReturnToOrigins,
|
|
314
|
+
};
|
|
315
|
+
const ui = validateUi({
|
|
316
|
+
locale: config.ui.locale,
|
|
317
|
+
productName: config.ui.productName,
|
|
318
|
+
supportText: config.ui.supportText,
|
|
319
|
+
...(config.ui.logoUrl ? { logoUrl: config.ui.logoUrl } : {}),
|
|
320
|
+
...options.ui,
|
|
321
|
+
});
|
|
322
|
+
const now = options.now ?? Date.now;
|
|
323
|
+
const logger = options.logger ?? NOOP_LOGGER;
|
|
324
|
+
const coreRoutes = config.routes;
|
|
325
|
+
const normalizedExtras = normalizeRoutes(legacyRoutes ?? {
|
|
326
|
+
basePath: coreRoutes.basePath,
|
|
327
|
+
startPath: coreRoutes.startPath,
|
|
328
|
+
loginPath: coreRoutes.loginPath,
|
|
329
|
+
callbackPath: coreRoutes.callbackPath,
|
|
330
|
+
logoutPath: coreRoutes.logoutPath,
|
|
331
|
+
sessionPath: coreRoutes.sessionPath,
|
|
332
|
+
signedOutPath: coreRoutes.signedOutPath,
|
|
333
|
+
errorPath: coreRoutes.errorPath,
|
|
334
|
+
});
|
|
335
|
+
const routes = normalizedExtras;
|
|
336
|
+
const cookiePath = normalizePath(options.cookiePath ?? "/", "cookiePath");
|
|
337
|
+
const transactionCookiePath = normalizePath(options.transactionCookiePath ??
|
|
338
|
+
config.routes.cookiePath, "transactionCookiePath");
|
|
339
|
+
if (config.redirectUri.pathname !== routes.callback) {
|
|
340
|
+
throw new AuthError("CONFIG_INVALID", "redirectUri pathname must match the configured callback route");
|
|
341
|
+
}
|
|
342
|
+
if (!pathContains(transactionCookiePath, routes.login) ||
|
|
343
|
+
!pathContains(transactionCookiePath, routes.callback)) {
|
|
344
|
+
throw new AuthError("CONFIG_INVALID", "transactionCookiePath must include the login and callback routes");
|
|
345
|
+
}
|
|
346
|
+
if (config.environment === "production" && !options.sessionStore) {
|
|
347
|
+
throw new AuthError("SESSION_STORE_UNSAFE", "A persistent sessionStore is required in production");
|
|
348
|
+
}
|
|
349
|
+
if (config.environment === "production" && !options.transactionStore) {
|
|
350
|
+
throw new AuthError("SESSION_STORE_UNSAFE", "A shared atomic transactionStore is required in production");
|
|
351
|
+
}
|
|
352
|
+
assertProductionSafeStore(options.sessionStore, config.environment, {
|
|
353
|
+
purpose: "session",
|
|
354
|
+
});
|
|
355
|
+
assertProductionSafeStore(options.transactionStore, config.environment, {
|
|
356
|
+
purpose: "transaction",
|
|
357
|
+
requireAtomicConsume: true,
|
|
358
|
+
});
|
|
359
|
+
const sessionStore = options.sessionStore ?? new MemorySessionStore(config.environment, { now });
|
|
360
|
+
const transactions = options.transactionStore ??
|
|
361
|
+
new MemoryAuthTransactionStore(config.environment, { now });
|
|
362
|
+
const oidc = options.oidcClient ??
|
|
363
|
+
(await VvpOidcClient.discover(config, sessionStore, { logger, now }));
|
|
364
|
+
const cookieName = options.cookieName ?? "vvp_session";
|
|
365
|
+
const transactionCookieName = options.transactionCookieName ?? "vvp_auth_transaction";
|
|
366
|
+
const transactionTtlSeconds = options.transactionTtlSeconds ?? 300;
|
|
367
|
+
if (!Number.isSafeInteger(transactionTtlSeconds) ||
|
|
368
|
+
transactionTtlSeconds < 30 ||
|
|
369
|
+
transactionTtlSeconds > 600) {
|
|
370
|
+
throw new AuthError("CONFIG_INVALID", "transactionTtlSeconds must be between 30 and 600");
|
|
371
|
+
}
|
|
372
|
+
const refreshBeforeExpirySeconds = options.refreshBeforeExpirySeconds ?? 60;
|
|
373
|
+
if (!Number.isSafeInteger(refreshBeforeExpirySeconds) ||
|
|
374
|
+
refreshBeforeExpirySeconds < 0 ||
|
|
375
|
+
refreshBeforeExpirySeconds > 600) {
|
|
376
|
+
throw new AuthError("CONFIG_INVALID", "refreshBeforeExpirySeconds must be between 0 and 600");
|
|
377
|
+
}
|
|
378
|
+
const secure = config.environment === "production";
|
|
379
|
+
const sessionCookie = {
|
|
380
|
+
httpOnly: true,
|
|
381
|
+
secure,
|
|
382
|
+
sameSite: "lax",
|
|
383
|
+
path: cookiePath,
|
|
384
|
+
maxAge: Math.min(config.sessionTtlSeconds, 7 * 24 * 60 * 60) * 1_000,
|
|
385
|
+
};
|
|
386
|
+
const transactionCookie = {
|
|
387
|
+
httpOnly: true,
|
|
388
|
+
secure,
|
|
389
|
+
sameSite: "lax",
|
|
390
|
+
path: transactionCookiePath,
|
|
391
|
+
maxAge: transactionTtlSeconds * 1_000,
|
|
392
|
+
};
|
|
393
|
+
const clearCookieOptions = {
|
|
394
|
+
httpOnly: true,
|
|
395
|
+
secure,
|
|
396
|
+
sameSite: "lax",
|
|
397
|
+
path: cookiePath,
|
|
398
|
+
};
|
|
399
|
+
const clearSession = (res) => res.clearCookie(cookieName, clearCookieOptions);
|
|
400
|
+
const clearTransaction = (res) => res.clearCookie(transactionCookieName, {
|
|
401
|
+
...clearCookieOptions,
|
|
402
|
+
path: transactionCookiePath,
|
|
403
|
+
});
|
|
404
|
+
logger.info(AUTH_EXPRESS_EVENTS.ready, {
|
|
405
|
+
environment: config.environment,
|
|
406
|
+
secureCookies: secure,
|
|
407
|
+
basePath: routes.basePath,
|
|
408
|
+
callbackPath: routes.callback,
|
|
409
|
+
signedOutPath: routes.signedOut,
|
|
410
|
+
cookiePath,
|
|
411
|
+
transactionCookiePath,
|
|
412
|
+
});
|
|
413
|
+
const correlate = (req, res, next) => {
|
|
414
|
+
const supplied = req.get("x-correlation-id");
|
|
415
|
+
req.vvpCorrelationId =
|
|
416
|
+
supplied && CORRELATION_PATTERN.test(supplied) ? supplied : randomUUID();
|
|
417
|
+
res.set("x-correlation-id", req.vvpCorrelationId);
|
|
418
|
+
next();
|
|
419
|
+
};
|
|
420
|
+
const authenticate = asyncHandler(async (req, res, next) => {
|
|
421
|
+
try {
|
|
422
|
+
const id = parseCookies(req.headers.cookie)[cookieName];
|
|
423
|
+
if (!id || !ID_PATTERN.test(id)) {
|
|
424
|
+
next();
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
let session = await sessionStore.get(id);
|
|
428
|
+
if (!session) {
|
|
429
|
+
clearSession(res);
|
|
430
|
+
next();
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
if (session.tokens.expiresAt !== undefined &&
|
|
434
|
+
session.tokens.expiresAt <=
|
|
435
|
+
now() + refreshBeforeExpirySeconds * 1_000) {
|
|
436
|
+
try {
|
|
437
|
+
session = await oidc.refreshSession(id);
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
await sessionStore.delete(id);
|
|
441
|
+
clearSession(res);
|
|
442
|
+
logger.warn(AUTH_EXPRESS_EVENTS.sessionRefreshFailed, {
|
|
443
|
+
correlationId: req.vvpCorrelationId,
|
|
444
|
+
});
|
|
445
|
+
next();
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
req.vvpActor = session.actor;
|
|
450
|
+
next();
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
clearSession(res);
|
|
454
|
+
logger.error(AUTH_EXPRESS_EVENTS.internalError, {
|
|
455
|
+
correlationId: req.vvpCorrelationId,
|
|
456
|
+
operation: "authenticate",
|
|
457
|
+
});
|
|
458
|
+
if (!res.headersSent) {
|
|
459
|
+
res.status(503).json({
|
|
460
|
+
error: "authentication_unavailable",
|
|
461
|
+
correlationId: req.vvpCorrelationId,
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
const unauthenticated = (req, res, behavior) => {
|
|
467
|
+
logger.info(AUTH_EXPRESS_EVENTS.accessDenied, {
|
|
468
|
+
correlationId: req.vvpCorrelationId,
|
|
469
|
+
reason: "unauthenticated",
|
|
470
|
+
mode: behavior.mode,
|
|
471
|
+
});
|
|
472
|
+
if (behavior.mode === "html") {
|
|
473
|
+
const returnTo = safeReturnTo(req.originalUrl, returnToOptions);
|
|
474
|
+
res.redirect(302, `${routes.start}?returnTo=${encodeURIComponent(returnTo)}`);
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
res.status(401).json({
|
|
478
|
+
error: "authentication_required",
|
|
479
|
+
correlationId: req.vvpCorrelationId,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const requireAuth = (behavior) => (req, res, next) => {
|
|
484
|
+
if (req.vvpActor)
|
|
485
|
+
next();
|
|
486
|
+
else
|
|
487
|
+
unauthenticated(req, res, behavior);
|
|
488
|
+
};
|
|
489
|
+
const authorize = (predicate, behavior) => (req, res, next) => {
|
|
490
|
+
if (!req.vvpActor) {
|
|
491
|
+
unauthenticated(req, res, behavior);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (predicate(req.vvpActor)) {
|
|
495
|
+
next();
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
logger.info(AUTH_EXPRESS_EVENTS.accessDenied, {
|
|
499
|
+
correlationId: req.vvpCorrelationId,
|
|
500
|
+
reason: "forbidden",
|
|
501
|
+
mode: behavior.mode,
|
|
502
|
+
});
|
|
503
|
+
if (behavior.mode === "html") {
|
|
504
|
+
res.status(403).type("text").send("Forbidden");
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
res.status(403).json({
|
|
508
|
+
error: "forbidden",
|
|
509
|
+
correlationId: req.vvpCorrelationId,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
const router = Router();
|
|
514
|
+
router.use(correlate);
|
|
515
|
+
const sendPage = (res, html, nonce) => {
|
|
516
|
+
res
|
|
517
|
+
.set("Cache-Control", "no-store")
|
|
518
|
+
.set("Pragma", "no-cache")
|
|
519
|
+
.set("Content-Security-Policy", `default-src 'none'; base-uri 'none'; frame-ancestors *; form-action 'self'; img-src 'self'; style-src 'nonce-${nonce}'; script-src 'nonce-${nonce}'`)
|
|
520
|
+
.set("Referrer-Policy", "no-referrer")
|
|
521
|
+
.set("X-Content-Type-Options", "nosniff")
|
|
522
|
+
.type("html")
|
|
523
|
+
.send(html);
|
|
524
|
+
};
|
|
525
|
+
const localSignedOutUrl = (() => {
|
|
526
|
+
const configuredPublicOrigin = config.publicOrigin;
|
|
527
|
+
return new URL(routes.signedOut, configuredPublicOrigin ?? config.redirectUri).href;
|
|
528
|
+
})();
|
|
529
|
+
const errorRedirect = (res, reason, correlationId) => {
|
|
530
|
+
const query = new URLSearchParams({ reason, correlationId });
|
|
531
|
+
res.redirect(302, `${routes.error}?${query.toString()}`);
|
|
532
|
+
};
|
|
533
|
+
router.get(routes.start, (req, res) => {
|
|
534
|
+
const returnTo = safeReturnTo(typeof req.query["returnTo"] === "string" ? req.query["returnTo"] : undefined, returnToOptions);
|
|
535
|
+
const href = returnTo === "/"
|
|
536
|
+
? routes.login
|
|
537
|
+
: `${routes.login}?returnTo=${encodeURIComponent(returnTo)}`;
|
|
538
|
+
const nonce = randomBytes(18).toString("base64url");
|
|
539
|
+
sendPage(res, page({
|
|
540
|
+
ui,
|
|
541
|
+
title: ui.text.startTitle,
|
|
542
|
+
body: ui.text.startBody,
|
|
543
|
+
actionHref: href,
|
|
544
|
+
actionText: ui.text.continueLogin,
|
|
545
|
+
nonce,
|
|
546
|
+
autoNavigate: true,
|
|
547
|
+
}), nonce);
|
|
548
|
+
});
|
|
549
|
+
router.get(routes.login, asyncHandler(async (req, res) => {
|
|
550
|
+
const returnTo = safeReturnTo(typeof req.query["returnTo"] === "string"
|
|
551
|
+
? req.query["returnTo"]
|
|
552
|
+
: undefined, returnToOptions);
|
|
553
|
+
const authorization = await oidc.createAuthorizationRequest();
|
|
554
|
+
const id = opaqueId();
|
|
555
|
+
await transactions.set({
|
|
556
|
+
id,
|
|
557
|
+
state: authorization.state,
|
|
558
|
+
nonce: authorization.nonce,
|
|
559
|
+
codeVerifier: authorization.codeVerifier,
|
|
560
|
+
returnTo,
|
|
561
|
+
expiresAt: now() + transactionTtlSeconds * 1_000,
|
|
562
|
+
}, transactionTtlSeconds);
|
|
563
|
+
res.cookie(transactionCookieName, id, transactionCookie);
|
|
564
|
+
logger.info(AUTH_EXPRESS_EVENTS.loginStarted, {
|
|
565
|
+
correlationId: req.vvpCorrelationId,
|
|
566
|
+
});
|
|
567
|
+
res.redirect(302, authorization.authorizationUrl.href);
|
|
568
|
+
}));
|
|
569
|
+
router.get(routes.callback, asyncHandler(async (req, res) => {
|
|
570
|
+
const state = typeof req.query["state"] === "string" ? req.query["state"] : "";
|
|
571
|
+
const id = parseCookies(req.headers.cookie)[transactionCookieName];
|
|
572
|
+
const transactionValidationReason = !id
|
|
573
|
+
? "transaction_cookie_missing"
|
|
574
|
+
: !ID_PATTERN.test(id)
|
|
575
|
+
? "transaction_cookie_malformed"
|
|
576
|
+
: !state
|
|
577
|
+
? "state_missing"
|
|
578
|
+
: undefined;
|
|
579
|
+
const hasWellFormedTransactionReference = Boolean(id && state && ID_PATTERN.test(id));
|
|
580
|
+
let consumeResult;
|
|
581
|
+
try {
|
|
582
|
+
consumeResult = hasWellFormedTransactionReference
|
|
583
|
+
? await transactions.consume(id, state)
|
|
584
|
+
: { status: "not_found" };
|
|
585
|
+
}
|
|
586
|
+
catch {
|
|
587
|
+
clearTransaction(res);
|
|
588
|
+
const consumeError = transactionConsumeError({
|
|
589
|
+
status: "ambiguous",
|
|
590
|
+
});
|
|
591
|
+
logger.error(AUTH_EXPRESS_EVENTS.callbackRejected, {
|
|
592
|
+
correlationId: req.vvpCorrelationId,
|
|
593
|
+
stage: consumeError.stage,
|
|
594
|
+
reason: consumeError.reason,
|
|
595
|
+
code: consumeError.code,
|
|
596
|
+
});
|
|
597
|
+
errorRedirect(res, "session_failed", req.vvpCorrelationId);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (consumeResult.status !== "ok") {
|
|
601
|
+
if (!hasWellFormedTransactionReference ||
|
|
602
|
+
consumeResult.status === "expired" ||
|
|
603
|
+
consumeResult.status === "already_consumed" ||
|
|
604
|
+
consumeResult.status === "ambiguous") {
|
|
605
|
+
clearTransaction(res);
|
|
606
|
+
}
|
|
607
|
+
const consumeError = transactionConsumeError(consumeResult);
|
|
608
|
+
logger.warn(AUTH_EXPRESS_EVENTS.callbackRejected, {
|
|
609
|
+
correlationId: req.vvpCorrelationId,
|
|
610
|
+
stage: "transaction_validation",
|
|
611
|
+
reason: transactionValidationReason ?? consumeError.reason,
|
|
612
|
+
code: consumeError.code,
|
|
613
|
+
});
|
|
614
|
+
const publicReason = consumeResult.status === "expired" ? "transaction_expired"
|
|
615
|
+
: consumeResult.status === "already_consumed"
|
|
616
|
+
? "transaction_already_used"
|
|
617
|
+
: consumeResult.status === "ambiguous"
|
|
618
|
+
? "session_failed"
|
|
619
|
+
: "transaction_missing";
|
|
620
|
+
errorRedirect(res, publicReason, req.vvpCorrelationId);
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const transaction = consumeResult.transaction;
|
|
624
|
+
clearTransaction(res);
|
|
625
|
+
try {
|
|
626
|
+
const callbackUrl = new URL(config.redirectUri.href);
|
|
627
|
+
callbackUrl.search = req.originalUrl.includes("?")
|
|
628
|
+
? req.originalUrl.slice(req.originalUrl.indexOf("?"))
|
|
629
|
+
: "";
|
|
630
|
+
const session = await oidc.handleCallback({
|
|
631
|
+
callbackUrl,
|
|
632
|
+
state: transaction.state,
|
|
633
|
+
nonce: transaction.nonce,
|
|
634
|
+
codeVerifier: transaction.codeVerifier,
|
|
635
|
+
...(req.vvpCorrelationId
|
|
636
|
+
? { correlationId: req.vvpCorrelationId }
|
|
637
|
+
: {}),
|
|
638
|
+
});
|
|
639
|
+
res.cookie(cookieName, session.id, sessionCookie);
|
|
640
|
+
logger.info(AUTH_EXPRESS_EVENTS.callbackSucceeded, {
|
|
641
|
+
correlationId: req.vvpCorrelationId,
|
|
642
|
+
stage: "session",
|
|
643
|
+
reason: "created",
|
|
644
|
+
});
|
|
645
|
+
res.redirect(302, transaction.returnTo);
|
|
646
|
+
}
|
|
647
|
+
catch (error) {
|
|
648
|
+
clearSession(res);
|
|
649
|
+
const code = error instanceof AuthError ? error.code : "AUTHORIZATION_FAILED";
|
|
650
|
+
const diagnostic = classifyAuthError(error);
|
|
651
|
+
logger.warn(AUTH_EXPRESS_EVENTS.callbackRejected, {
|
|
652
|
+
correlationId: req.vvpCorrelationId,
|
|
653
|
+
stage: error instanceof AuthError ? error.stage : "callback",
|
|
654
|
+
reason: diagnostic.reason,
|
|
655
|
+
code,
|
|
656
|
+
...(diagnostic.details.library
|
|
657
|
+
? { library: diagnostic.details.library }
|
|
658
|
+
: {}),
|
|
659
|
+
...(diagnostic.details.libraryCode
|
|
660
|
+
? { libraryCode: diagnostic.details.libraryCode }
|
|
661
|
+
: {}),
|
|
662
|
+
...(diagnostic.details.httpStatus
|
|
663
|
+
? { httpStatus: diagnostic.details.httpStatus }
|
|
664
|
+
: {}),
|
|
665
|
+
...(diagnostic.details.claim
|
|
666
|
+
? { claim: diagnostic.details.claim }
|
|
667
|
+
: {}),
|
|
668
|
+
});
|
|
669
|
+
errorRedirect(res, publicCallbackReason(error), req.vvpCorrelationId);
|
|
670
|
+
}
|
|
671
|
+
}));
|
|
672
|
+
router.get(routes.signedOut, (_req, res) => {
|
|
673
|
+
const nonce = randomBytes(18).toString("base64url");
|
|
674
|
+
sendPage(res, page({
|
|
675
|
+
ui,
|
|
676
|
+
title: ui.text.signedOutTitle,
|
|
677
|
+
body: ui.text.signedOutBody,
|
|
678
|
+
actionHref: routes.start,
|
|
679
|
+
actionText: ui.text.signInAgain,
|
|
680
|
+
nonce,
|
|
681
|
+
}), nonce);
|
|
682
|
+
});
|
|
683
|
+
router.get(routes.error, (req, res) => {
|
|
684
|
+
const suppliedReason = typeof req.query["reason"] === "string" ? req.query["reason"] : "unknown";
|
|
685
|
+
const reason = PUBLIC_ERROR_REASONS.has(suppliedReason)
|
|
686
|
+
? suppliedReason
|
|
687
|
+
: "unknown";
|
|
688
|
+
const suppliedCorrelationId = typeof req.query["correlationId"] === "string"
|
|
689
|
+
? req.query["correlationId"]
|
|
690
|
+
: req.vvpCorrelationId;
|
|
691
|
+
const correlationId = CORRELATION_PATTERN.test(suppliedCorrelationId)
|
|
692
|
+
? suppliedCorrelationId
|
|
693
|
+
: req.vvpCorrelationId;
|
|
694
|
+
const locale = ui.locale ?? requestLanguage(req);
|
|
695
|
+
const nonce = randomBytes(18).toString("base64url");
|
|
696
|
+
sendPage(res, page({
|
|
697
|
+
ui,
|
|
698
|
+
title: ui.text.errorTitle,
|
|
699
|
+
body: ERROR_MESSAGES[locale][reason],
|
|
700
|
+
actionHref: routes.start,
|
|
701
|
+
actionText: ui.text.tryAgain,
|
|
702
|
+
correlationId,
|
|
703
|
+
nonce,
|
|
704
|
+
}), nonce);
|
|
705
|
+
});
|
|
706
|
+
router.post(routes.logout, asyncHandler(async (req, res) => {
|
|
707
|
+
const origin = req.get("origin");
|
|
708
|
+
const referer = req.get("referer");
|
|
709
|
+
let sourceOrigin;
|
|
710
|
+
try {
|
|
711
|
+
sourceOrigin = origin ? new URL(origin).origin : referer
|
|
712
|
+
? new URL(referer).origin
|
|
713
|
+
: undefined;
|
|
714
|
+
}
|
|
715
|
+
catch {
|
|
716
|
+
sourceOrigin = undefined;
|
|
717
|
+
}
|
|
718
|
+
if (sourceOrigin !== config.redirectUri.origin) {
|
|
719
|
+
logger.warn(AUTH_EXPRESS_EVENTS.logoutRejected, {
|
|
720
|
+
correlationId: req.vvpCorrelationId,
|
|
721
|
+
stage: "request_validation",
|
|
722
|
+
reason: "cross_origin",
|
|
723
|
+
});
|
|
724
|
+
res.status(403).type("text").send("Logout request was rejected.");
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const id = parseCookies(req.headers.cookie)[cookieName];
|
|
728
|
+
clearSession(res);
|
|
729
|
+
clearTransaction(res);
|
|
730
|
+
if (!id || !ID_PATTERN.test(id)) {
|
|
731
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutLocalSessionDeleted, {
|
|
732
|
+
correlationId: req.vvpCorrelationId,
|
|
733
|
+
hadSession: false,
|
|
734
|
+
});
|
|
735
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutSucceeded, {
|
|
736
|
+
correlationId: req.vvpCorrelationId,
|
|
737
|
+
hadSession: false,
|
|
738
|
+
stage: "local",
|
|
739
|
+
});
|
|
740
|
+
const localRedirect = localSignedOutUrl;
|
|
741
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutRedirectCreated, {
|
|
742
|
+
correlationId: req.vvpCorrelationId,
|
|
743
|
+
destination: "signed_out",
|
|
744
|
+
});
|
|
745
|
+
res.redirect(303, localRedirect);
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
try {
|
|
749
|
+
const logoutUrl = await oidc.logout(id);
|
|
750
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutLocalSessionDeleted, {
|
|
751
|
+
correlationId: req.vvpCorrelationId,
|
|
752
|
+
hadSession: true,
|
|
753
|
+
});
|
|
754
|
+
if ((logoutUrl.protocol !== "https:" && logoutUrl.protocol !== "http:") ||
|
|
755
|
+
(logoutUrl.protocol !== "https:" && config.environment === "production")) {
|
|
756
|
+
logger.warn(AUTH_EXPRESS_EVENTS.logoutInvalidRedirect, {
|
|
757
|
+
correlationId: req.vvpCorrelationId,
|
|
758
|
+
stage: "redirect_validation",
|
|
759
|
+
reason: "insecure_provider_redirect",
|
|
760
|
+
});
|
|
761
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutRedirectCreated, {
|
|
762
|
+
correlationId: req.vvpCorrelationId,
|
|
763
|
+
destination: "local_recovery",
|
|
764
|
+
});
|
|
765
|
+
res.redirect(303, localSignedOutUrl);
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutRedirectCreated, {
|
|
769
|
+
correlationId: req.vvpCorrelationId,
|
|
770
|
+
destination: "provider",
|
|
771
|
+
});
|
|
772
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutSucceeded, {
|
|
773
|
+
correlationId: req.vvpCorrelationId,
|
|
774
|
+
hadSession: true,
|
|
775
|
+
stage: "local_and_redirect",
|
|
776
|
+
});
|
|
777
|
+
res.redirect(303, logoutUrl.href);
|
|
778
|
+
}
|
|
779
|
+
catch {
|
|
780
|
+
await sessionStore.delete(id);
|
|
781
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutLocalSessionDeleted, {
|
|
782
|
+
correlationId: req.vvpCorrelationId,
|
|
783
|
+
hadSession: true,
|
|
784
|
+
});
|
|
785
|
+
logger.warn(AUTH_EXPRESS_EVENTS.logoutProviderRejected, {
|
|
786
|
+
correlationId: req.vvpCorrelationId,
|
|
787
|
+
stage: "provider_redirect",
|
|
788
|
+
reason: "redirect_creation_failed",
|
|
789
|
+
});
|
|
790
|
+
logger.info(AUTH_EXPRESS_EVENTS.logoutRedirectCreated, {
|
|
791
|
+
correlationId: req.vvpCorrelationId,
|
|
792
|
+
destination: "local_recovery",
|
|
793
|
+
});
|
|
794
|
+
res.redirect(303, localSignedOutUrl);
|
|
795
|
+
}
|
|
796
|
+
}));
|
|
797
|
+
router.get(routes.session, (_req, res, next) => {
|
|
798
|
+
res.set("cache-control", "no-store");
|
|
799
|
+
res.set("pragma", "no-cache");
|
|
800
|
+
next();
|
|
801
|
+
}, authenticate, asyncHandler(async (req, res) => {
|
|
802
|
+
if (!req.vvpActor) {
|
|
803
|
+
res.status(401).json({
|
|
804
|
+
error: "authentication_required",
|
|
805
|
+
correlationId: req.vvpCorrelationId,
|
|
806
|
+
});
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const id = parseCookies(req.headers.cookie)[cookieName];
|
|
810
|
+
const session = id ? await sessionStore.get(id) : null;
|
|
811
|
+
if (!session) {
|
|
812
|
+
res.status(401).json({
|
|
813
|
+
error: "authentication_required",
|
|
814
|
+
correlationId: req.vvpCorrelationId,
|
|
815
|
+
});
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
res.json(toPublicSession(session));
|
|
819
|
+
}));
|
|
820
|
+
const safeAuthError = (_error, req, res, _next) => {
|
|
821
|
+
logger.error(AUTH_EXPRESS_EVENTS.internalError, {
|
|
822
|
+
correlationId: req.vvpCorrelationId,
|
|
823
|
+
operation: "auth_route",
|
|
824
|
+
});
|
|
825
|
+
if (!res.headersSent) {
|
|
826
|
+
if (req.method === "GET" && req.path !== routes.session) {
|
|
827
|
+
errorRedirect(res, req.path === routes.callback ? "unknown" : "provider_unavailable", req.vvpCorrelationId);
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
res.status(500).json({
|
|
831
|
+
error: "authentication_unavailable",
|
|
832
|
+
correlationId: req.vvpCorrelationId,
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
router.use(safeAuthError);
|
|
838
|
+
const applicationAuthenticate = (req, res, next) => {
|
|
839
|
+
correlate(req, res, (error) => {
|
|
840
|
+
if (error) {
|
|
841
|
+
next(error);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
authenticate(req, res, next);
|
|
845
|
+
});
|
|
846
|
+
};
|
|
847
|
+
return {
|
|
848
|
+
config,
|
|
849
|
+
router,
|
|
850
|
+
authenticate: applicationAuthenticate,
|
|
851
|
+
requireAuth,
|
|
852
|
+
requireRealmRole: (role, behavior) => [
|
|
853
|
+
requireAuth(behavior),
|
|
854
|
+
authorize((actor) => hasRealmRole(actor, role), behavior),
|
|
855
|
+
],
|
|
856
|
+
requireClientRole: (role, behavior) => [
|
|
857
|
+
requireAuth(behavior),
|
|
858
|
+
authorize((actor) => hasClientRole(actor, role, behavior.clientId ?? config.clientId), behavior),
|
|
859
|
+
],
|
|
860
|
+
requireAnyClientRole: (roles, behavior) => [
|
|
861
|
+
requireAuth(behavior),
|
|
862
|
+
authorize((actor) => hasAnyClientRole(actor, roles, behavior.clientId ?? config.clientId), behavior),
|
|
863
|
+
],
|
|
864
|
+
createLoginUrl: (returnTo) => {
|
|
865
|
+
const safe = safeReturnTo(returnTo, returnToOptions);
|
|
866
|
+
return safe === "/" ? routes.start :
|
|
867
|
+
`${routes.start}?returnTo=${encodeURIComponent(safe)}`;
|
|
868
|
+
},
|
|
869
|
+
createLoginLink: (returnTo) => ({
|
|
870
|
+
href: (() => {
|
|
871
|
+
const safe = safeReturnTo(returnTo, returnToOptions);
|
|
872
|
+
return safe === "/" ? routes.start :
|
|
873
|
+
`${routes.start}?returnTo=${encodeURIComponent(safe)}`;
|
|
874
|
+
})(),
|
|
875
|
+
target: "_top",
|
|
876
|
+
rel: "noopener noreferrer",
|
|
877
|
+
}),
|
|
878
|
+
hasClientRole: (actor, role) => hasClientRole(actor, role, config.clientId),
|
|
879
|
+
hasAnyClientRole: (actor, roles) => hasAnyClientRole(actor, roles, config.clientId),
|
|
880
|
+
routes,
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,cAAc,EACd,yBAAyB,EACzB,uBAAuB,GAWxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,MAAM,GAMP,MAAM,SAAS,CAAC;AAWjB,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,KAAK,EAAE,gBAAgB;IACvB,YAAY,EAAE,wBAAwB;IACtC,iBAAiB,EAAE,6BAA6B;IAChD,gBAAgB,EAAE,4BAA4B;IAC9C,eAAe,EAAE,2BAA2B;IAC5C,cAAc,EAAE,0BAA0B;IAC1C,yBAAyB,EAAE,uCAAuC;IAClE,qBAAqB,EAAE,kCAAkC;IACzD,sBAAsB,EAAE,mCAAmC;IAC3D,qBAAqB,EAAE,kCAAkC;IACzD,oBAAoB,EAAE,iCAAiC;IACvD,YAAY,EAAE,wBAAwB;IACtC,aAAa,EAAE,yBAAyB;CAChC,CAAC;AAwBX,MAAM,OAAO,0BAA0B;IAC5B,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC9C,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,IAAI,CAAe;IAE5B,YACE,WAA+B,EAC/B,UAAkC,EAAE;QAEpC,IAAI,WAAW,KAAK,YAAY,EAAE,CAAC;YACjC,MAAM,IAAI,SAAS,CACjB,sBAAsB,EACtB,2DAA2D,CAC5D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,GAAG,CACP,WAA4B,EAC5B,UAAkB;QAElB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE;YAChC,GAAG,eAAe,CAAC,WAAW,CAAC;YAC/B,SAAS,EAAE,IAAI,CAAC,GAAG,CACjB,WAAW,CAAC,SAAS,EACrB,IAAI,CAAC,IAAI,EAAE,GAAG,UAAU,GAAG,KAAK,CACjC;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CACX,EAAU,EACV,aAAqB;QAErB,KAAK,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACrD,IAAI,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE;gBAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,WAAW;aAClE,CAAC;QACJ,CAAC;QACD,IAAI,WAAW,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACzB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,CAAC;YACzD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QACtC,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;QAC9C,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC;IACrE,CAAC;CACF;AA4ID,MAAM,WAAW,GAAe;IAC9B,KAAK,KAAI,CAAC;IACV,IAAI,KAAI,CAAC;IACT,IAAI,KAAI,CAAC;IACT,KAAK,KAAI,CAAC;CACX,CAAC;AACF,MAAM,UAAU,GAAG,yBAAyB,CAAC;AAC7C,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AAEvD,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAClB,UAAU,EACV,CAAC,SAAS,EAAE,EAAE,CACZ,CAAC;QACC,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,QAAQ;QACb,GAAG,EAAE,OAAO;KACb,CAAC,CAAC,SAAS,CAAE,CACjB,CAAC;AACJ,CAAC;AAOD,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAoB;IACtD,qBAAqB,EAAE,qBAAqB,EAAE,0BAA0B;IACxE,iBAAiB,EAAE,yBAAyB,EAAE,sBAAsB;IACpE,gBAAgB,EAAE,qBAAqB,EAAE,SAAS;CACnD,CAAC,CAAC;AAEH,MAAM,cAAc,GAA2D;IAC7E,EAAE,EAAE;QACF,mBAAmB,EAAE,6DAA6D;QAClF,mBAAmB,EAAE,0DAA0D;QAC/E,wBAAwB,EAAE,oEAAoE;QAC9F,eAAe,EAAE,qDAAqD;QACtE,uBAAuB,EAAE,uEAAuE;QAChG,oBAAoB,EAAE,4DAA4D;QAClF,cAAc,EAAE,wDAAwD;QACxE,mBAAmB,EAAE,6DAA6D;QAClF,OAAO,EAAE,4BAA4B;KACtC;IACD,EAAE,EAAE;QACF,mBAAmB,EAAE,sDAAsD;QAC3E,mBAAmB,EAAE,2CAA2C;QAChE,wBAAwB,EAAE,0DAA0D;QACpF,eAAe,EAAE,2DAA2D;QAC5E,uBAAuB,EAAE,mEAAmE;QAC5F,oBAAoB,EAAE,oEAAoE;QAC1F,cAAc,EAAE,0DAA0D;QAC1E,mBAAmB,EAAE,iEAAiE;QACtF,OAAO,EAAE,iCAAiC;KAC3C;CACF,CAAC;AAEF,SAAS,UAAU,CAAC,OAAkC;IACpD,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC;IACvC,MAAM,QAAQ,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;QACjC,aAAa,EAAE,kBAAkB,EAAE,UAAU,EAAE,SAAS;QACxD,SAAS,EAAE,4CAA4C;QACvD,cAAc,EAAE,qBAAqB,EAAE,aAAa,EAAE,yBAAyB;QAC/E,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe;QACzD,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW;KAC9C,CAAC,CAAC,CAAC;QACF,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,gBAAgB;QAC9D,SAAS,EAAE,0DAA0D;QACrE,cAAc,EAAE,qBAAqB,EAAE,aAAa,EAAE,wBAAwB;QAC9E,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc;QACtD,QAAQ,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe;KAC1D,CAAC;IACF,IAAI,OAA2B,CAAC;IAChC,IAAI,OAAO,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;YAC/D,IACE,MAAM,CAAC,MAAM,KAAK,qBAAqB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBAC3E,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;gBACtE,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI;gBAC5B,MAAM,IAAI,KAAK,EAAE,CAAC;YACpB,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,SAAS,CAAC,gBAAgB,EAAE,mEAAmE,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC;IACD,OAAO;QACL,MAAM;QACN,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,KAAK;QAC1C,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,EAAE;QACvC,IAAI,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE;QACvC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CAAC,KASb;IACC,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IACrB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO;QACrB,CAAC,CAAC,0BAA0B,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW;QAC7D,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW;QAC5B,CAAC,CAAC,sBAAsB,UAAU,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM;QACxD,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa;QACnC,CAAC,CAAC,+BAA+B,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,qBAAqB;QAC7H,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY;QAC/B,CAAC,CAAC,kBAAkB,KAAK,CAAC,KAAK,oCAAoC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,uBAAuB;QACnJ,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;cACK,EAAE,CAAC,MAAM;SACd,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,KAAK,CAAC,KAAK;;;;;;;qBAO/C,IAAI,SAAS,UAAU,CAAC,EAAE,CAAC,WAAW,CAAC;oBACxC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;0BAClD,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,6CAA6C,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC;EAC7H,OAAO,GAAG,SAAS,UAAU,MAAM,gBAAgB,CAAC;AACtD,CAAC;AAED,SAAS,QAAQ;IACf,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,YAAY,CAAC,MAA0B;IAC9C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,SAAS,GAAG,CAAC;YAAE,SAAS;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,KAAa;IACpD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,aAAa,CAAC,KAAa,EAAE,KAAa;IACjD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QACpE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,SAAS,CAAC,gBAAgB,EAAE,GAAG,KAAK,qCAAqC,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,SAAS,CAAC,gBAAgB,EAAE,GAAG,KAAK,gCAAgC,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB,EAAE,KAAyB,EAAE,QAAgB;IAC9E,MAAM,KAAK,GAAG,KAAK,IAAI,QAAQ,CAAC;IAChC,OAAO,aAAa,CAClB,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,KAAK,EAAE,EACtD,YAAY,CACb,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,QAA0B,EAAE;IACnD,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,QAAQ,IAAI,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG;QACb,QAAQ;QACR,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC;QACnE,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC;QACnE,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC;QAC/E,MAAM,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC;QACvE,OAAO,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC;QACtE,SAAS,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,SAAS,EAAE,YAAY,CAAC;QACpF,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC;KACpE,CAAC;IACF,MAAM,KAAK,GAAG;QACZ,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO;QAC1E,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK;KAC/B,CAAC;IACF,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,gBAAgB,EAAE,sCAAsC,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,UAAkB,EAAE,WAAmB;IAC3D,OAAO,UAAU,KAAK,GAAG,IAAI,WAAW,KAAK,UAAU;QACrD,WAAW,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,eAAe,CAAC,GAAY;IACnC,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChE,OAAO,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,GAAG,KAAK,YAAY,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;IACnG,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5F,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACjE,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IACD,IACE,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC9E,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QACpF,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAClD,CAAC;QACD,OAAO,yBAAyB,CAAC;IACnC,CAAC;IACD,IACE,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC1D,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EACvD,CAAC;QACD,OAAO,sBAAsB,CAAC;IAChC,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAClF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,YAAY,CACnB,OAA2E;IAE3E,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAY;IACnC,OAAO,GAAG,CAAC,QAAQ,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAwB,EAAE,IAAY;IACjE,OAAO,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,KAAK,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,KAAwB,EACxB,IAAY,EACZ,QAAgB;IAEhB,OAAO,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,KAAK,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAwB,EACxB,KAAwB,EACxB,QAAgB;IAEhB,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAA6B;IAE7B,0EAA0E;IAC1E,4EAA4E;IAC5E,mEAAmE;IACnE,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IACpC,MAAM,WAAW,GAAoB,YAAY;QAC/C,CAAC,CAAC;YACE,GAAG,OAAO,CAAC,MAAM;YACjB,MAAM,EAAE;gBACN,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM;gBACxB,GAAG,CAAC,YAAY,CAAC,QAAQ,KAAK,SAAS;oBACrC,CAAC,CAAC,EAAE,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7C,GAAG,CAAC,YAAY,CAAC,SAAS,IAAI,YAAY,CAAC,KAAK;oBAC9C,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrE,GAAG,CAAC,YAAY,CAAC,SAAS,IAAI,YAAY,CAAC,KAAK;oBAC9C,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrE,GAAG,CAAC,YAAY,CAAC,YAAY,IAAI,YAAY,CAAC,QAAQ;oBACpD,CAAC,CAAC,EAAE,YAAY,EAAE,YAAY,CAAC,YAAY,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9E,GAAG,CAAC,YAAY,CAAC,UAAU,IAAI,YAAY,CAAC,MAAM;oBAChD,CAAC,CAAC,EAAE,UAAU,EAAE,YAAY,CAAC,UAAU,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxE,GAAG,CAAC,YAAY,CAAC,WAAW,IAAI,YAAY,CAAC,OAAO;oBAClD,CAAC,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,WAAW,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3E,GAAG,CAAC,YAAY,CAAC,aAAa,IAAI,YAAY,CAAC,SAAS;oBACtD,CAAC,CAAC;wBACE,aAAa,EACX,YAAY,CAAC,aAAa,IAAI,YAAY,CAAC,SAAS;qBACvD,CAAC,CAAC,CAAC,EAAE,CAAC;gBACX,GAAG,CAAC,YAAY,CAAC,SAAS,IAAI,YAAY,CAAC,KAAK;oBAC9C,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrE,GAAG,CAAC,YAAY,CAAC,UAAU,KAAK,SAAS;oBACvC,CAAC,CAAC,EAAE,UAAU,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClD;SACF;QACH,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACnB,MAAM,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,eAAe,GAAG;QACtB,UAAU,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM;QACpE,cAAc,EAAE,MAAM,CAAC,sBAAsB;KAC9C,CAAC;IACF,MAAM,EAAE,GAAG,UAAU,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM;QACxB,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW;QAClC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW;QAClC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,GAAG,OAAO,CAAC,EAAE;KACd,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,MAIzB,CAAC;IACF,MAAM,gBAAgB,GAAG,eAAe,CAAC,YAAY,IAAI;QACvD,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,UAAU,EAAE,UAAU,CAAC,UAAU;QACjC,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,aAAa,EAAE,UAAU,CAAC,aAAa;QACvC,SAAS,EAAE,UAAU,CAAC,SAAS;KAChC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,gBAAgB,CAAC;IAChC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,UAAU,IAAI,GAAG,EAAE,YAAY,CAAC,CAAC;IAC1E,MAAM,qBAAqB,GAAG,aAAa,CACzC,OAAO,CAAC,qBAAqB;QAC3B,MAAM,CAAC,MAAM,CAAC,UAAU,EAC1B,uBAAuB,CACxB,CAAC;IACF,IAAI,MAAM,CAAC,WAAW,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpD,MAAM,IAAI,SAAS,CACjB,gBAAgB,EAChB,+DAA+D,CAChE,CAAC;IACJ,CAAC;IACD,IACE,CAAC,YAAY,CAAC,qBAAqB,EAAE,MAAM,CAAC,KAAK,CAAC;QAClD,CAAC,YAAY,CAAC,qBAAqB,EAAE,MAAM,CAAC,QAAQ,CAAC,EACrD,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,gBAAgB,EAChB,kEAAkE,CACnE,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,WAAW,KAAK,YAAY,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QACjE,MAAM,IAAI,SAAS,CACjB,sBAAsB,EACtB,qDAAqD,CACtD,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,WAAW,KAAK,YAAY,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACrE,MAAM,IAAI,SAAS,CACjB,sBAAsB,EACtB,4DAA4D,CAC7D,CAAC;IACJ,CAAC;IACD,yBAAyB,CAAC,OAAO,CAAC,YAAa,EAAE,MAAM,CAAC,WAAW,EAAE;QACnE,OAAO,EAAE,SAAS;KACnB,CAAC,CAAC;IACH,yBAAyB,CAAC,OAAO,CAAC,gBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE;QACvE,OAAO,EAAE,aAAa;QACtB,oBAAoB,EAAE,IAAI;KAC3B,CAAC,CAAC;IACH,MAAM,YAAY,GAChB,OAAO,CAAC,YAAY,IAAI,IAAI,kBAAkB,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9E,MAAM,YAAY,GAChB,OAAO,CAAC,gBAAgB;QACxB,IAAI,0BAA0B,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9D,MAAM,IAAI,GACR,OAAO,CAAC,UAAU;QAClB,CAAC,MAAM,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC;IACvD,MAAM,qBAAqB,GACzB,OAAO,CAAC,qBAAqB,IAAI,sBAAsB,CAAC;IAC1D,MAAM,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,IAAI,GAAG,CAAC;IACnE,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,qBAAqB,CAAC;QAC5C,qBAAqB,GAAG,EAAE;QAC1B,qBAAqB,GAAG,GAAG,EAC3B,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,gBAAgB,EAChB,kDAAkD,CACnD,CAAC;IACJ,CAAC;IACD,MAAM,0BAA0B,GAC9B,OAAO,CAAC,0BAA0B,IAAI,EAAE,CAAC;IAC3C,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,0BAA0B,CAAC;QACjD,0BAA0B,GAAG,CAAC;QAC9B,0BAA0B,GAAG,GAAG,EAChC,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,gBAAgB,EAChB,sDAAsD,CACvD,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,KAAK,YAAY,CAAC;IACnD,MAAM,aAAa,GAAG;QACpB,QAAQ,EAAE,IAAI;QACd,MAAM;QACN,QAAQ,EAAE,KAAc;QACxB,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK;KACrE,CAAC;IACF,MAAM,iBAAiB,GAAG;QACxB,QAAQ,EAAE,IAAI;QACd,MAAM;QACN,QAAQ,EAAE,KAAc;QACxB,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,qBAAqB,GAAG,KAAK;KACtC,CAAC;IACF,MAAM,kBAAkB,GAAG;QACzB,QAAQ,EAAE,IAAI;QACd,MAAM;QACN,QAAQ,EAAE,KAAc;QACxB,IAAI,EAAE,UAAU;KACjB,CAAC;IACF,MAAM,YAAY,GAAG,CAAC,GAAa,EAAE,EAAE,CACrC,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;IAClD,MAAM,gBAAgB,GAAG,CAAC,GAAa,EAAE,EAAE,CACzC,GAAG,CAAC,WAAW,CAAC,qBAAqB,EAAE;QACrC,GAAG,kBAAkB;QACrB,IAAI,EAAE,qBAAqB;KAC5B,CAAC,CAAC;IAEL,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE;QACrC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,aAAa,EAAE,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,MAAM,CAAC,QAAQ;QAC7B,aAAa,EAAE,MAAM,CAAC,SAAS;QAC/B,UAAU;QACV,qBAAqB;KACtB,CAAC,CAAC;IAEH,MAAM,SAAS,GAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAC7C,GAAG,CAAC,gBAAgB;YAClB,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;QAC3E,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAClD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzD,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YACxD,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;gBAChC,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YACD,IAAI,OAAO,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACzC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,YAAY,CAAC,GAAG,CAAC,CAAC;gBAClB,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YACD,IACE,OAAO,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS;gBACtC,OAAO,CAAC,MAAM,CAAC,SAAS;oBACtB,GAAG,EAAE,GAAG,0BAA0B,GAAG,KAAK,EAC5C,CAAC;gBACD,IAAI,CAAC;oBACH,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;gBAC1C,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBAC9B,YAAY,CAAC,GAAG,CAAC,CAAC;oBAClB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,oBAAoB,EAAE;wBACpD,aAAa,EAAE,GAAG,CAAC,gBAAgB;qBACpC,CAAC,CAAC;oBACH,IAAI,EAAE,CAAC;oBACP,OAAO;gBACT,CAAC;YACH,CAAC;YACD,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;YAC7B,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,YAAY,CAAC,GAAG,CAAC,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,aAAa,EAAE;gBAC9C,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,SAAS,EAAE,cAAc;aAC1B,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,KAAK,EAAE,4BAA4B;oBACnC,aAAa,EAAE,GAAG,CAAC,gBAAgB;iBACpC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,CACtB,GAAY,EACZ,GAAa,EACb,QAAwB,EACxB,EAAE;QACF,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE;YAC5C,aAAa,EAAE,GAAG,CAAC,gBAAgB;YACnC,MAAM,EAAE,iBAAiB;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;SACpB,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;YAChE,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,yBAAyB;gBAChC,aAAa,EAAE,GAAG,CAAC,gBAAgB;aACpC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,QAAwB,EAAkB,EAAE,CAC/D,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACjB,IAAI,GAAG,CAAC,QAAQ;YAAE,IAAI,EAAE,CAAC;;YACpB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC,CAAC;IAEJ,MAAM,SAAS,GAAG,CAChB,SAAoC,EACpC,QAAwB,EACR,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACtC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAClB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YACpC,OAAO;QACT,CAAC;QACD,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE;YAC5C,aAAa,EAAE,GAAG,CAAC,gBAAgB;YACnC,MAAM,EAAE,WAAW;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;SACpB,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,WAAW;gBAClB,aAAa,EAAE,GAAG,CAAC,gBAAgB;aACpC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtB,MAAM,QAAQ,GAAG,CAAC,GAAa,EAAE,IAAY,EAAE,KAAa,EAAE,EAAE;QAC9D,GAAG;aACA,GAAG,CAAC,eAAe,EAAE,UAAU,CAAC;aAChC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC;aACzB,GAAG,CACF,yBAAyB,EACzB,gHAAgH,KAAK,wBAAwB,KAAK,GAAG,CACtJ;aACA,GAAG,CAAC,iBAAiB,EAAE,aAAa,CAAC;aACrC,GAAG,CAAC,wBAAwB,EAAE,SAAS,CAAC;aACxC,IAAI,CAAC,MAAM,CAAC;aACZ,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC,CAAC;IACF,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE;QAC9B,MAAM,sBAAsB,GAAI,MAA8C,CAAC,YAAY,CAAC;QAC5F,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,sBAAsB,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC;IACtF,CAAC,CAAC,EAAE,CAAC;IACL,MAAM,aAAa,GAAG,CACpB,GAAa,EACb,MAAyB,EACzB,aAAqB,EACrB,EAAE;QACF,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;QAC7D,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACpC,MAAM,QAAQ,GAAG,YAAY,CAC3B,OAAO,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,EAC7E,eAAe,CAChB,CAAC;QACF,MAAM,IAAI,GAAG,QAAQ,KAAK,GAAG;YAC3B,CAAC,CAAC,MAAM,CAAC,KAAK;YACd,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACpD,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;YACjB,EAAE;YACF,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU;YACzB,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS;YACvB,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa;YACjC,KAAK;YACL,YAAY,EAAE,IAAI;SACnB,CAAC,EAAE,KAAK,CAAC,CAAC;IACb,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,CACR,MAAM,CAAC,KAAK,EACZ,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,QAAQ,GAAG,YAAY,CAC3B,OAAO,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,QAAQ;YACvC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;YACvB,CAAC,CAAC,SAAS,EACb,eAAe,CAChB,CAAC;QACF,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAC9D,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;QACtB,MAAM,YAAY,CAAC,GAAG,CACpB;YACE,EAAE;YACF,KAAK,EAAE,aAAa,CAAC,KAAK;YAC1B,KAAK,EAAE,aAAa,CAAC,KAAK;YAC1B,YAAY,EAAE,aAAa,CAAC,YAAY;YACxC,QAAQ;YACR,SAAS,EAAE,GAAG,EAAE,GAAG,qBAAqB,GAAG,KAAK;SACjD,EACD,qBAAqB,CACtB,CAAC;QACF,GAAG,CAAC,MAAM,CAAC,qBAAqB,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE;YAC5C,aAAa,EAAE,GAAG,CAAC,gBAAgB;SACpC,CAAC,CAAC;QACH,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC,CAAC,CACH,CAAC;IACF,MAAM,CAAC,GAAG,CACR,MAAM,CAAC,QAAQ,EACf,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,KAAK,GACT,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC;QACnE,MAAM,2BAA2B,GAAG,CAAC,EAAE;YACrC,CAAC,CAAC,4BAA4B;YAC9B,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpB,CAAC,CAAC,8BAA8B;gBAChC,CAAC,CAAC,CAAC,KAAK;oBACN,CAAC,CAAC,eAAe;oBACjB,CAAC,CAAC,SAAS,CAAC;QAClB,MAAM,iCAAiC,GAAG,OAAO,CAC/C,EAAE,IAAI,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CACnC,CAAC;QACF,IAAI,aAA4C,CAAC;QACjD,IAAI,CAAC;YACH,aAAa,GAAG,iCAAiC;gBAC/C,CAAC,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,EAAG,EAAE,KAAK,CAAC;gBACxC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACtB,MAAM,YAAY,GAAG,uBAAuB,CAAkB;gBAC5D,MAAM,EAAE,WAAW;aACpB,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,EAAE;gBACjD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,IAAI,EAAE,YAAY,CAAC,IAAI;aACxB,CAAC,CAAC;YACH,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,CAAC,gBAAiB,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QACD,IAAI,aAAa,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAClC,IACE,CAAC,iCAAiC;gBAClC,aAAa,CAAC,MAAM,KAAK,SAAS;gBAClC,aAAa,CAAC,MAAM,KAAK,kBAAkB;gBAC3C,aAAa,CAAC,MAAM,KAAK,WAAW,EACpC,CAAC;gBACD,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;YACD,MAAM,YAAY,GAAG,uBAAuB,CAAC,aAAa,CAAC,CAAC;YAC5D,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,EAAE;gBAChD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,KAAK,EAAE,wBAAwB;gBAC/B,MAAM,EAAE,2BAA2B,IAAI,YAAY,CAAC,MAAM;gBAC1D,IAAI,EAAE,YAAY,CAAC,IAAI;aACxB,CAAC,CAAC;YACH,MAAM,YAAY,GAChB,aAAa,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB;gBACxD,CAAC,CAAC,aAAa,CAAC,MAAM,KAAK,kBAAkB;oBAC3C,CAAC,CAAC,0BAA0B;oBAC5B,CAAC,CAAC,aAAa,CAAC,MAAM,KAAK,WAAW;wBACpC,CAAC,CAAC,gBAAgB;wBAClB,CAAC,CAAC,qBAAqB,CAAC;YAChC,aAAa,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,CAAC,gBAAiB,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QACD,MAAM,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC;QAC9C,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACrD,WAAW,CAAC,MAAM,GAAG,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAChD,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACrD,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC;gBACxC,WAAW;gBACX,KAAK,EAAE,WAAW,CAAC,KAAK;gBACxB,KAAK,EAAE,WAAW,CAAC,KAAK;gBACxB,YAAY,EAAE,WAAW,CAAC,YAAY;gBACtC,GAAG,CAAC,GAAG,CAAC,gBAAgB;oBACtB,CAAC,CAAC,EAAE,aAAa,EAAE,GAAG,CAAC,gBAAgB,EAAE;oBACzC,CAAC,CAAC,EAAE,CAAC;aACR,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;YAClD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,iBAAiB,EAAE;gBACjD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;YACH,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,GAAG,CAAC,CAAC;YAClB,MAAM,IAAI,GACR,KAAK,YAAY,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC;YACnE,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,EAAE;gBAChD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,KAAK,EAAE,KAAK,YAAY,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU;gBAC5D,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,IAAI;gBACJ,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO;oBAC5B,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE;oBACzC,CAAC,CAAC,EAAE,CAAC;gBACP,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW;oBAChC,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE;oBACjD,CAAC,CAAC,EAAE,CAAC;gBACP,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU;oBAC/B,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,UAAU,EAAE;oBAC/C,CAAC,CAAC,EAAE,CAAC;gBACP,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK;oBAC1B,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE;oBACrC,CAAC,CAAC,EAAE,CAAC;aACR,CAAC,CAAC;YACH,aAAa,CACX,GAAG,EACH,oBAAoB,CAAC,KAAK,CAAC,EAC3B,GAAG,CAAC,gBAAiB,CACtB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACzC,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACpD,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;YACjB,EAAE;YACF,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc;YAC7B,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa;YAC3B,UAAU,EAAE,MAAM,CAAC,KAAK;YACxB,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW;YAC/B,KAAK;SACN,CAAC,EAAE,KAAK,CAAC,CAAC;IACb,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACpC,MAAM,cAAc,GAClB,OAAO,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,cAAmC,CAAC;YAC1E,CAAC,CAAC,cAAmC;YACrC,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,qBAAqB,GACzB,OAAO,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,QAAQ;YAC5C,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC;YAC5B,CAAC,CAAC,GAAG,CAAC,gBAAiB,CAAC;QAC5B,MAAM,aAAa,GAAG,mBAAmB,CAAC,IAAI,CAAC,qBAAqB,CAAC;YACnE,CAAC,CAAC,qBAAqB;YACvB,CAAC,CAAC,GAAG,CAAC,gBAAiB,CAAC;QAC1B,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACpD,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;YACjB,EAAE;YACF,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU;YACzB,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;YACpC,UAAU,EAAE,MAAM,CAAC,KAAK;YACxB,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ;YAC5B,aAAa;YACb,KAAK;SACN,CAAC,EAAE,KAAK,CAAC,CAAC;IACb,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,MAAM,EACb,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,YAAgC,CAAC;QACrC,IAAI,CAAC;YACH,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;gBACtD,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM;gBACzB,CAAC,CAAC,SAAS,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,YAAY,GAAG,SAAS,CAAC;QAC3B,CAAC;QACD,IAAI,YAAY,KAAK,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,cAAc,EAAE;gBAC9C,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,KAAK,EAAE,oBAAoB;gBAC3B,MAAM,EAAE,cAAc;aACvB,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAClE,OAAO;QACT,CAAC;QACD,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACxD,YAAY,CAAC,GAAG,CAAC,CAAC;QAClB,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,yBAAyB,EAAE;gBACzD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,UAAU,EAAE,KAAK;aAClB,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,eAAe,EAAE;gBAC/C,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,UAAU,EAAE,KAAK;gBACjB,KAAK,EAAE,OAAO;aACf,CAAC,CAAC;YACH,MAAM,aAAa,GAAG,iBAAiB,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE;gBACrD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,WAAW,EAAE,YAAY;aAC1B,CAAC,CAAC;YACH,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,yBAAyB,EAAE;gBACzD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,UAAU,EAAE,IAAI;aACjB,CAAC,CAAC;YACH,IACE,CAAC,SAAS,CAAC,QAAQ,KAAK,QAAQ,IAAI,SAAS,CAAC,QAAQ,KAAK,OAAO,CAAC;gBACnE,CAAC,SAAS,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,WAAW,KAAK,YAAY,CAAC,EACxE,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE;oBACrD,aAAa,EAAE,GAAG,CAAC,gBAAgB;oBACnC,KAAK,EAAE,qBAAqB;oBAC5B,MAAM,EAAE,4BAA4B;iBACrC,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE;oBACrD,aAAa,EAAE,GAAG,CAAC,gBAAgB;oBACnC,WAAW,EAAE,gBAAgB;iBAC9B,CAAC,CAAC;gBACH,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;gBACrC,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE;gBACrD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,WAAW,EAAE,UAAU;aACxB,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,eAAe,EAAE;gBAC/C,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,UAAU,EAAE,IAAI;gBAChB,KAAK,EAAE,oBAAoB;aAC5B,CAAC,CAAC;YACH,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,yBAAyB,EAAE;gBACzD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,UAAU,EAAE,IAAI;aACjB,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,sBAAsB,EAAE;gBACtD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,KAAK,EAAE,mBAAmB;gBAC1B,MAAM,EAAE,0BAA0B;aACnC,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE;gBACrD,aAAa,EAAE,GAAG,CAAC,gBAAgB;gBACnC,WAAW,EAAE,gBAAgB;aAC9B,CAAC,CAAC;YACH,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC7C,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QACrC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC9B,IAAI,EAAE,CAAC;IACT,CAAC,EAAE,YAAY,EAAE,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC/C,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,yBAAyB;gBAChC,aAAa,EAAE,GAAG,CAAC,gBAAgB;aACpC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,yBAAyB;gBAChC,aAAa,EAAE,GAAG,CAAC,gBAAgB;aACpC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC,CAAC;IACJ,MAAM,aAAa,GAAwB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACrE,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,aAAa,EAAE;YAC9C,aAAa,EAAE,GAAG,CAAC,gBAAgB;YACnC,SAAS,EAAE,YAAY;SACxB,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;gBACxD,aAAa,CACX,GAAG,EACH,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,sBAAsB,EACjE,GAAG,CAAC,gBAAiB,CACtB,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,KAAK,EAAE,4BAA4B;oBACnC,aAAa,EAAE,GAAG,CAAC,gBAAgB;iBACpC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAE1B,MAAM,uBAAuB,GAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACjE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAe,EAAE,EAAE;YACtC,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,KAAK,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO;QACL,MAAM;QACN,MAAM;QACN,YAAY,EAAE,uBAAuB;QACrC,WAAW;QACX,gBAAgB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;YACpC,WAAW,CAAC,QAAQ,CAAC;YACrB,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;SAC1D;QACD,iBAAiB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;YACrC,WAAW,CAAC,QAAQ,CAAC;YACrB,SAAS,CACP,CAAC,KAAK,EAAE,EAAE,CACR,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAClE,QAAQ,CACT;SACF;QACD,oBAAoB,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC;YACzC,WAAW,CAAC,QAAQ,CAAC;YACrB,SAAS,CACP,CAAC,KAAK,EAAE,EAAE,CACR,gBAAgB,CACd,KAAK,EACL,KAAK,EACL,QAAQ,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CACrC,EACH,QAAQ,CACT;SACF;QACD,cAAc,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC3B,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;YACrD,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAClC,GAAG,MAAM,CAAC,KAAK,aAAa,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,CAAC;QACD,eAAe,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC9B,IAAI,EAAE,CAAC,GAAG,EAAE;gBACV,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;gBACrD,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBAClC,GAAG,MAAM,CAAC,KAAK,aAAa,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,CAAC,CAAC,EAAE;YACJ,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,qBAAqB;SAC3B,CAAC;QACF,aAAa,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC;QAC3E,gBAAgB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CACjC,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC;QACjD,MAAM;KACP,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dreadkn1ght123/auth-express",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Secure Express integration for VVP authentication",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"express": "^5.1.0",
|
|
23
|
+
"@dreadkn1ght123/auth-types": "^0.2.0",
|
|
24
|
+
"@dreadkn1ght123/auth-core": "^0.2.0"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": true
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/express": "^5.0.3",
|
|
32
|
+
"@types/node": "^22.15.0",
|
|
33
|
+
"@types/supertest": "^6.0.3",
|
|
34
|
+
"supertest": "^7.1.4"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -b",
|
|
38
|
+
"typecheck": "tsc -b --pretty false && tsc -p tsconfig.test.json --noEmit --pretty false",
|
|
39
|
+
"test": "vitest run"
|
|
40
|
+
}
|
|
41
|
+
}
|