nterminal 1.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.
Files changed (197) hide show
  1. package/.env.example +12 -0
  2. package/LICENSE +674 -0
  3. package/README.md +181 -0
  4. package/assets/brand/app-icon-1024.png +0 -0
  5. package/assets/brand/app-icon-384.png +0 -0
  6. package/assets/brand/apple-touch-icon-360.png +0 -0
  7. package/assets/brand/favicon-32.png +0 -0
  8. package/assets/brand/favicon-64.png +0 -0
  9. package/assets/brand/favicon-96.png +0 -0
  10. package/assets/brand/favicon.svg +4 -0
  11. package/assets/brand/nterminal-mark-64.png +0 -0
  12. package/assets/brand/nterminal-mark.svg +4 -0
  13. package/assets/brand/nterminal-wordmark-486x68.png +0 -0
  14. package/assets/brand/nterminal-wordmark.svg +3 -0
  15. package/assets/screenshot/scr.png +0 -0
  16. package/bin/nterminal.js +114 -0
  17. package/dist/client/apple-touch-icon.png +0 -0
  18. package/dist/client/assets/MarkdownPreview-BeDi-V7k.js +29 -0
  19. package/dist/client/assets/MesloLGS-NF-Bold-Italic-DwFsXcwX.ttf +0 -0
  20. package/dist/client/assets/MesloLGS-NF-Bold-kN-HYz-g.ttf +0 -0
  21. package/dist/client/assets/MesloLGS-NF-Italic-CMg1T6-G.ttf +0 -0
  22. package/dist/client/assets/MesloLGS-NF-Regular-Cxr8pvCI.ttf +0 -0
  23. package/dist/client/assets/index-BQkKYjXb.js +33 -0
  24. package/dist/client/assets/index-WqeS39wU.css +1 -0
  25. package/dist/client/assets/notifications/character-2258.mp4 +0 -0
  26. package/dist/client/assets/notifications/character-2260.mp4 +0 -0
  27. package/dist/client/assets/notifications/character-2272.mp4 +0 -0
  28. package/dist/client/brand/nterminal-mark-64.png +0 -0
  29. package/dist/client/brand/nterminal-mark.svg +4 -0
  30. package/dist/client/brand/nterminal-wordmark-486x68.png +0 -0
  31. package/dist/client/brand/nterminal-wordmark.svg +3 -0
  32. package/dist/client/icons/app-icon-1024.png +0 -0
  33. package/dist/client/icons/app-icon-384.png +0 -0
  34. package/dist/client/icons/favicon-32.png +0 -0
  35. package/dist/client/icons/favicon-64.png +0 -0
  36. package/dist/client/icons/favicon-96.png +0 -0
  37. package/dist/client/icons/favicon.svg +4 -0
  38. package/dist/client/index.html +21 -0
  39. package/dist/client/manifest.webmanifest +24 -0
  40. package/dist/scripts/generate-secrets.js +3 -0
  41. package/dist/scripts/generate-secrets.js.map +1 -0
  42. package/dist/scripts/onboarding.js +814 -0
  43. package/dist/scripts/onboarding.js.map +1 -0
  44. package/dist/scripts/proxySetup.js +1007 -0
  45. package/dist/scripts/proxySetup.js.map +1 -0
  46. package/dist/server/agent/agentAuth.d.ts +6 -0
  47. package/dist/server/agent/agentAuth.js +35 -0
  48. package/dist/server/agent/agentAuth.js.map +1 -0
  49. package/dist/server/agent/agentProxy.d.ts +5 -0
  50. package/dist/server/agent/agentProxy.js +63 -0
  51. package/dist/server/agent/agentProxy.js.map +1 -0
  52. package/dist/server/agent/agentRoutes.d.ts +9 -0
  53. package/dist/server/agent/agentRoutes.js +327 -0
  54. package/dist/server/agent/agentRoutes.js.map +1 -0
  55. package/dist/server/agent/agentWebSocketProxy.d.ts +3 -0
  56. package/dist/server/agent/agentWebSocketProxy.js +65 -0
  57. package/dist/server/agent/agentWebSocketProxy.js.map +1 -0
  58. package/dist/server/auth/authService.d.ts +100 -0
  59. package/dist/server/auth/authService.js +415 -0
  60. package/dist/server/auth/authService.js.map +1 -0
  61. package/dist/server/auth/cookies.d.ts +11 -0
  62. package/dist/server/auth/cookies.js +39 -0
  63. package/dist/server/auth/cookies.js.map +1 -0
  64. package/dist/server/auth/ipMatch.d.ts +14 -0
  65. package/dist/server/auth/ipMatch.js +103 -0
  66. package/dist/server/auth/ipMatch.js.map +1 -0
  67. package/dist/server/auth/rateLimit.d.ts +17 -0
  68. package/dist/server/auth/rateLimit.js +25 -0
  69. package/dist/server/auth/rateLimit.js.map +1 -0
  70. package/dist/server/auth/totpService.d.ts +10 -0
  71. package/dist/server/auth/totpService.js +37 -0
  72. package/dist/server/auth/totpService.js.map +1 -0
  73. package/dist/server/config.d.ts +27 -0
  74. package/dist/server/config.js +138 -0
  75. package/dist/server/config.js.map +1 -0
  76. package/dist/server/files/fileExplorerService.d.ts +38 -0
  77. package/dist/server/files/fileExplorerService.js +551 -0
  78. package/dist/server/files/fileExplorerService.js.map +1 -0
  79. package/dist/server/files/rootToken.d.ts +51 -0
  80. package/dist/server/files/rootToken.js +139 -0
  81. package/dist/server/files/rootToken.js.map +1 -0
  82. package/dist/server/http.d.ts +13 -0
  83. package/dist/server/http.js +69 -0
  84. package/dist/server/http.js.map +1 -0
  85. package/dist/server/index.d.ts +1 -0
  86. package/dist/server/index.js +45 -0
  87. package/dist/server/index.js.map +1 -0
  88. package/dist/server/routes/agentManagementRoutes.d.ts +9 -0
  89. package/dist/server/routes/agentManagementRoutes.js +304 -0
  90. package/dist/server/routes/agentManagementRoutes.js.map +1 -0
  91. package/dist/server/routes/authRoutes.d.ts +10 -0
  92. package/dist/server/routes/authRoutes.js +95 -0
  93. package/dist/server/routes/authRoutes.js.map +1 -0
  94. package/dist/server/routes/fileRoutes.d.ts +11 -0
  95. package/dist/server/routes/fileRoutes.js +185 -0
  96. package/dist/server/routes/fileRoutes.js.map +1 -0
  97. package/dist/server/routes/notificationAssetRoutes.d.ts +9 -0
  98. package/dist/server/routes/notificationAssetRoutes.js +280 -0
  99. package/dist/server/routes/notificationAssetRoutes.js.map +1 -0
  100. package/dist/server/routes/securityRoutes.d.ts +7 -0
  101. package/dist/server/routes/securityRoutes.js +53 -0
  102. package/dist/server/routes/securityRoutes.js.map +1 -0
  103. package/dist/server/routes/socketBackpressure.d.ts +26 -0
  104. package/dist/server/routes/socketBackpressure.js +63 -0
  105. package/dist/server/routes/socketBackpressure.js.map +1 -0
  106. package/dist/server/routes/terminalLayoutRoutes.d.ts +9 -0
  107. package/dist/server/routes/terminalLayoutRoutes.js +108 -0
  108. package/dist/server/routes/terminalLayoutRoutes.js.map +1 -0
  109. package/dist/server/routes/terminalRoutes.d.ts +14 -0
  110. package/dist/server/routes/terminalRoutes.js +177 -0
  111. package/dist/server/routes/terminalRoutes.js.map +1 -0
  112. package/dist/server/routes/terminalWebSocket.d.ts +9 -0
  113. package/dist/server/routes/terminalWebSocket.js +129 -0
  114. package/dist/server/routes/terminalWebSocket.js.map +1 -0
  115. package/dist/server/routes/totpRoutes.d.ts +7 -0
  116. package/dist/server/routes/totpRoutes.js +46 -0
  117. package/dist/server/routes/totpRoutes.js.map +1 -0
  118. package/dist/server/routes/updateRoutes.d.ts +7 -0
  119. package/dist/server/routes/updateRoutes.js +24 -0
  120. package/dist/server/routes/updateRoutes.js.map +1 -0
  121. package/dist/server/routes/uploadRoutes.d.ts +9 -0
  122. package/dist/server/routes/uploadRoutes.js +95 -0
  123. package/dist/server/routes/uploadRoutes.js.map +1 -0
  124. package/dist/server/storage/fileStore.d.ts +90 -0
  125. package/dist/server/storage/fileStore.js +275 -0
  126. package/dist/server/storage/fileStore.js.map +1 -0
  127. package/dist/server/system/stats.d.ts +2 -0
  128. package/dist/server/system/stats.js +37 -0
  129. package/dist/server/system/stats.js.map +1 -0
  130. package/dist/server/terminal/NodePtyAdapter.d.ts +4 -0
  131. package/dist/server/terminal/NodePtyAdapter.js +14 -0
  132. package/dist/server/terminal/NodePtyAdapter.js.map +1 -0
  133. package/dist/server/terminal/PtyAdapter.d.ts +57 -0
  134. package/dist/server/terminal/PtyAdapter.js +2 -0
  135. package/dist/server/terminal/PtyAdapter.js.map +1 -0
  136. package/dist/server/terminal/TerminalManager.d.ts +74 -0
  137. package/dist/server/terminal/TerminalManager.js +561 -0
  138. package/dist/server/terminal/TerminalManager.js.map +1 -0
  139. package/dist/server/terminal/TmuxPtyAdapter.d.ts +25 -0
  140. package/dist/server/terminal/TmuxPtyAdapter.js +543 -0
  141. package/dist/server/terminal/TmuxPtyAdapter.js.map +1 -0
  142. package/dist/server/terminal/codexTranscriptSource.d.ts +9 -0
  143. package/dist/server/terminal/codexTranscriptSource.js +144 -0
  144. package/dist/server/terminal/codexTranscriptSource.js.map +1 -0
  145. package/dist/server/terminal/cwdResolver.d.ts +8 -0
  146. package/dist/server/terminal/cwdResolver.js +37 -0
  147. package/dist/server/terminal/cwdResolver.js.map +1 -0
  148. package/dist/server/terminal/outputBuffer.d.ts +7 -0
  149. package/dist/server/terminal/outputBuffer.js +17 -0
  150. package/dist/server/terminal/outputBuffer.js.map +1 -0
  151. package/dist/server/terminal/transcriptHistory.d.ts +7 -0
  152. package/dist/server/terminal/transcriptHistory.js +315 -0
  153. package/dist/server/terminal/transcriptHistory.js.map +1 -0
  154. package/dist/server/update/gitUpdate.d.ts +27 -0
  155. package/dist/server/update/gitUpdate.js +241 -0
  156. package/dist/server/update/gitUpdate.js.map +1 -0
  157. package/dist/server/uploads/uploadPaths.d.ts +18 -0
  158. package/dist/server/uploads/uploadPaths.js +116 -0
  159. package/dist/server/uploads/uploadPaths.js.map +1 -0
  160. package/dist/server/uploads/uploadService.d.ts +21 -0
  161. package/dist/server/uploads/uploadService.js +230 -0
  162. package/dist/server/uploads/uploadService.js.map +1 -0
  163. package/dist/shared/layoutState.d.ts +6 -0
  164. package/dist/shared/layoutState.js +115 -0
  165. package/dist/shared/layoutState.js.map +1 -0
  166. package/dist/shared/notificationAssets.d.ts +9 -0
  167. package/dist/shared/notificationAssets.js +27 -0
  168. package/dist/shared/notificationAssets.js.map +1 -0
  169. package/dist/shared/protocol.d.ts +308 -0
  170. package/dist/shared/protocol.js +29 -0
  171. package/dist/shared/protocol.js.map +1 -0
  172. package/dist/shared/types.d.ts +56 -0
  173. package/dist/shared/types.js +2 -0
  174. package/dist/shared/types.js.map +1 -0
  175. package/docs/assets/nterminal-workspace.png +0 -0
  176. package/docs/configuration.md +97 -0
  177. package/docs/features.md +126 -0
  178. package/docs/onboarding.md +122 -0
  179. package/docs/operations.md +112 -0
  180. package/docs/terminal-history.md +54 -0
  181. package/package.json +85 -0
  182. package/public/apple-touch-icon.png +0 -0
  183. package/public/assets/notifications/character-2258.mp4 +0 -0
  184. package/public/assets/notifications/character-2260.mp4 +0 -0
  185. package/public/assets/notifications/character-2272.mp4 +0 -0
  186. package/public/brand/nterminal-mark-64.png +0 -0
  187. package/public/brand/nterminal-mark.svg +4 -0
  188. package/public/brand/nterminal-wordmark-486x68.png +0 -0
  189. package/public/brand/nterminal-wordmark.svg +3 -0
  190. package/public/icons/app-icon-1024.png +0 -0
  191. package/public/icons/app-icon-384.png +0 -0
  192. package/public/icons/favicon-32.png +0 -0
  193. package/public/icons/favicon-64.png +0 -0
  194. package/public/icons/favicon-96.png +0 -0
  195. package/public/icons/favicon.svg +4 -0
  196. package/public/manifest.webmanifest +24 -0
  197. package/scripts/nterminalctl +588 -0
@@ -0,0 +1,65 @@
1
+ import WebSocket from 'ws';
2
+ export function proxyAgentWebSocket(browserSocket, agent, terminalId) {
3
+ const agentUrl = `${agent.url.replace(/^http/, 'ws')}/api/agent/terminals/${encodeURIComponent(terminalId)}/ws`;
4
+ const agentSocket = new WebSocket(agentUrl, { headers: { Authorization: `Bearer ${agent.token}` } });
5
+ // Pending entries hold both the raw data and the frame type so the relay
6
+ // never silently changes a text frame into a binary one — the browser's
7
+ // ws handler ignores non-string data, which manifests as "agent terminal
8
+ // pane opens but has no output and no input ever takes effect".
9
+ const pendingFromBrowser = [];
10
+ agentSocket.on('open', () => {
11
+ for (const entry of pendingFromBrowser) {
12
+ agentSocket.send(entry.data, { binary: entry.binary });
13
+ }
14
+ pendingFromBrowser.length = 0;
15
+ });
16
+ agentSocket.on('message', (data, isBinary) => {
17
+ if (browserSocket.readyState === WebSocket.OPEN) {
18
+ browserSocket.send(data, { binary: isBinary });
19
+ }
20
+ });
21
+ browserSocket.on('message', (data, isBinary) => {
22
+ if (agentSocket.readyState === WebSocket.OPEN) {
23
+ agentSocket.send(data, { binary: isBinary });
24
+ }
25
+ else if (agentSocket.readyState === WebSocket.CONNECTING) {
26
+ pendingFromBrowser.push({ data, binary: isBinary });
27
+ }
28
+ });
29
+ agentSocket.on('close', (code, reason) => {
30
+ if (browserSocket.readyState === WebSocket.OPEN) {
31
+ // Reserved codes 1005/1006/1015 (and anything <1000) cannot be sent
32
+ // back over the wire — ws throws synchronously on close() if we try.
33
+ // Map them to 1011 (internal error) so an agent that goes away
34
+ // mid-update doesn't bring the main process down.
35
+ const safeCode = code >= 1000 && code !== 1005 && code !== 1006 && code !== 1015 ? code : 1011;
36
+ const safeReason = Buffer.isBuffer(reason) && reason.length <= 123 ? reason : undefined;
37
+ try {
38
+ browserSocket.close(safeCode, safeReason);
39
+ }
40
+ catch {
41
+ // Last-resort: give up cleanly so a malformed reason can't crash us.
42
+ try {
43
+ browserSocket.terminate();
44
+ }
45
+ catch { /* swallow */ }
46
+ }
47
+ }
48
+ });
49
+ browserSocket.on('close', () => {
50
+ if (agentSocket.readyState === WebSocket.OPEN || agentSocket.readyState === WebSocket.CONNECTING) {
51
+ agentSocket.close();
52
+ }
53
+ });
54
+ agentSocket.on('error', () => {
55
+ if (browserSocket.readyState === WebSocket.OPEN) {
56
+ browserSocket.close(1011, 'agent error');
57
+ }
58
+ });
59
+ browserSocket.on('error', () => {
60
+ if (agentSocket.readyState === WebSocket.OPEN || agentSocket.readyState === WebSocket.CONNECTING) {
61
+ agentSocket.close();
62
+ }
63
+ });
64
+ }
65
+ //# sourceMappingURL=agentWebSocketProxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentWebSocketProxy.js","sourceRoot":"","sources":["../../../src/server/agent/agentWebSocketProxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ import type { AppConfig } from '../config.js';
2
+ import type { FileStore } from '../storage/fileStore.js';
3
+ import { InMemoryRateLimit } from './rateLimit.js';
4
+ import type { TotpService } from './totpService.js';
5
+ export declare class AuthError extends Error {
6
+ readonly code: string;
7
+ readonly statusCode: number;
8
+ constructor(code: string, message: string, statusCode?: number);
9
+ }
10
+ export interface PasswordSession {
11
+ sessionId: string;
12
+ expiresAt: string;
13
+ }
14
+ export interface LoginResult {
15
+ session: PasswordSession;
16
+ deviceToken: string;
17
+ }
18
+ export interface AuthContext {
19
+ ip?: string | null | undefined;
20
+ userAgent?: string | null | undefined;
21
+ rememberNetwork?: boolean | undefined;
22
+ deviceToken?: string | null | undefined;
23
+ clientKey?: string | undefined;
24
+ }
25
+ export interface TrustedDeviceSummary {
26
+ id: string;
27
+ label: string;
28
+ createdAt: string;
29
+ lastSeenAt: string;
30
+ current: boolean;
31
+ }
32
+ export interface IpRuleSummary {
33
+ id: string;
34
+ value: string;
35
+ label: string;
36
+ createdAt: string;
37
+ }
38
+ export interface AuthServiceOptions {
39
+ now?: () => number;
40
+ passwordRateLimit?: InMemoryRateLimit;
41
+ totpService?: TotpService;
42
+ }
43
+ export declare class AuthService {
44
+ private readonly config;
45
+ private readonly store;
46
+ private readonly now;
47
+ private readonly passwordRateLimit;
48
+ private readonly sessions;
49
+ private readonly totpService;
50
+ constructor(config: AppConfig, store: FileStore, options?: AuthServiceOptions);
51
+ setupPassword(password: string, ctx?: AuthContext): Promise<LoginResult>;
52
+ loginWithPassword(password: string, otp?: string, ctx?: AuthContext): Promise<LoginResult>;
53
+ reauthWithOtp(otp: string | undefined, ctx?: AuthContext): Promise<PasswordSession>;
54
+ setupTotp(sessionId: string | undefined, ip?: string | null): Promise<{
55
+ secret: string;
56
+ qrDataUrl: string;
57
+ }>;
58
+ activateTotp(sessionId: string | undefined, secret: string, otp: string, ip?: string | null): Promise<void>;
59
+ disableTotp(sessionId: string | undefined, ip?: string | null): Promise<void>;
60
+ isTotpEnabled(): Promise<boolean>;
61
+ validateSession(sessionId: string | undefined, ip?: string | null, options?: {
62
+ destroy?: boolean;
63
+ }): Promise<boolean>;
64
+ getSessionStatus(sessionId: string | undefined, ctx?: {
65
+ ip?: string | null | undefined;
66
+ deviceToken?: string | null | undefined;
67
+ }): Promise<{
68
+ passwordSet: boolean;
69
+ authenticated: boolean;
70
+ totpEnabled: boolean;
71
+ deviceTrusted: boolean;
72
+ currentIpWhitelisted: boolean;
73
+ expiresAt: string | null;
74
+ }>;
75
+ requireSession(request: {
76
+ cookies?: Record<string, string | undefined>;
77
+ headers?: Record<string, string | string[] | undefined>;
78
+ ip?: string;
79
+ }): Promise<{
80
+ sessionId: string;
81
+ } | null>;
82
+ logout(sessionId: string | undefined, deviceToken?: string | null): Promise<void>;
83
+ listTrustedDevices(currentDeviceToken?: string | null): Promise<TrustedDeviceSummary[]>;
84
+ revokeTrustedDevice(id: string): Promise<void>;
85
+ listIpRules(): Promise<IpRuleSummary[]>;
86
+ addIpRule(value: string, label: string): Promise<IpRuleSummary>;
87
+ removeIpRule(id: string): Promise<void>;
88
+ private createSession;
89
+ private buildTrustedDevice;
90
+ private pruneDevices;
91
+ private findValidDevice;
92
+ private deviceMatchesToken;
93
+ private hashDeviceToken;
94
+ private maybeAddIp;
95
+ private validatePassword;
96
+ private hashPassword;
97
+ private verifyPassword;
98
+ private safeEqual;
99
+ private parseCookieHeader;
100
+ }
@@ -0,0 +1,415 @@
1
+ import crypto from 'node:crypto';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { promisify } from 'node:util';
4
+ import { InMemoryRateLimit } from './rateLimit.js';
5
+ import { normalizeIp, ipMatchesAny, isValidIpRule, isWithinSessionNetwork } from './ipMatch.js';
6
+ const scrypt = promisify(crypto.scrypt);
7
+ const deviceTtlMs = 30 * 24 * 60 * 60 * 1000;
8
+ export class AuthError extends Error {
9
+ code;
10
+ statusCode;
11
+ constructor(code, message, statusCode = 400) {
12
+ super(message);
13
+ this.code = code;
14
+ this.statusCode = statusCode;
15
+ }
16
+ }
17
+ export class AuthService {
18
+ config;
19
+ store;
20
+ now;
21
+ passwordRateLimit;
22
+ sessions = new Map();
23
+ totpService;
24
+ constructor(config, store, options = {}) {
25
+ this.config = config;
26
+ this.store = store;
27
+ this.now = options.now ?? Date.now;
28
+ this.passwordRateLimit =
29
+ options.passwordRateLimit ??
30
+ new InMemoryRateLimit({
31
+ limit: 5,
32
+ windowMs: 60_000,
33
+ now: this.now
34
+ });
35
+ this.totpService = options.totpService ?? null;
36
+ }
37
+ async setupPassword(password, ctx = {}) {
38
+ this.validatePassword(password);
39
+ const state = await this.store.read();
40
+ if (state.passwordCredential) {
41
+ throw new AuthError('PASSWORD_ALREADY_SET', 'Password is already set', 409);
42
+ }
43
+ const timestamp = new Date(this.now()).toISOString();
44
+ const salt = crypto.randomBytes(16).toString('base64url');
45
+ const credential = {
46
+ algorithm: 'scrypt',
47
+ hash: await this.hashPassword(password, salt),
48
+ salt,
49
+ createdAt: timestamp,
50
+ updatedAt: timestamp
51
+ };
52
+ const { token: deviceToken, record: device } = this.buildTrustedDevice(ctx);
53
+ const ip = normalizeIp(ctx.ip);
54
+ await this.store.update((current) => {
55
+ if (current.passwordCredential) {
56
+ throw new AuthError('PASSWORD_ALREADY_SET', 'Password is already set', 409);
57
+ }
58
+ return {
59
+ ...current,
60
+ passwordCredential: credential,
61
+ trustedDevices: [device],
62
+ ipWhitelist: this.maybeAddIp(current.ipWhitelist, ip, ctx.rememberNetwork)
63
+ };
64
+ }, { flush: 'immediate' });
65
+ const session = this.createSession(ip, device.id);
66
+ return { session, deviceToken };
67
+ }
68
+ async loginWithPassword(password, otp, ctx = {}) {
69
+ const state = await this.store.read();
70
+ const credential = state.passwordCredential;
71
+ if (!credential) {
72
+ throw new AuthError('PASSWORD_NOT_SET', 'Password is not set', 409);
73
+ }
74
+ const rateLimitKey = `password:${ctx.clientKey ?? 'default'}`;
75
+ const rate = this.passwordRateLimit.consume(rateLimitKey);
76
+ if (!rate.allowed) {
77
+ throw new AuthError('RATE_LIMITED', 'Too many password attempts', 429);
78
+ }
79
+ if (!(await this.verifyPassword(password, credential))) {
80
+ throw new AuthError('INVALID_PASSWORD', 'Invalid password', 401);
81
+ }
82
+ const totpCredential = state.totpCredential;
83
+ if (totpCredential) {
84
+ if (!otp) {
85
+ throw new AuthError('OTP_REQUIRED', 'OTP code is required', 401);
86
+ }
87
+ if (!this.totpService?.verify(totpCredential.secret, otp)) {
88
+ throw new AuthError('INVALID_OTP', 'Invalid OTP code', 401);
89
+ }
90
+ }
91
+ this.passwordRateLimit.reset(rateLimitKey);
92
+ const { token: deviceToken, record: device } = this.buildTrustedDevice(ctx);
93
+ const ip = normalizeIp(ctx.ip);
94
+ await this.store.update((current) => {
95
+ const devices = this.pruneDevices(current.trustedDevices).filter((d) => !this.deviceMatchesToken(ctx.deviceToken, d));
96
+ return {
97
+ ...current,
98
+ trustedDevices: [...devices, device],
99
+ ipWhitelist: this.maybeAddIp(current.ipWhitelist, ip, ctx.rememberNetwork)
100
+ };
101
+ }, { flush: 'immediate' });
102
+ const session = this.createSession(ip, device.id);
103
+ return { session, deviceToken };
104
+ }
105
+ async reauthWithOtp(otp, ctx = {}) {
106
+ const state = await this.store.read();
107
+ const device = this.findValidDevice(ctx.deviceToken, state.trustedDevices);
108
+ if (!device) {
109
+ throw new AuthError('DEVICE_NOT_TRUSTED', 'This device is not trusted', 401);
110
+ }
111
+ const ip = normalizeIp(ctx.ip);
112
+ const totpCredential = state.totpCredential;
113
+ const ipTrusted = ipMatchesAny(ip, state.ipWhitelist);
114
+ // OTP-only reauth is only meaningful once TOTP is enabled. Without it, a leftover device
115
+ // cookie (e.g. between password setup and TOTP activation, or after disabling 2FA) could mint
116
+ // a session with no second factor — force a full password login instead.
117
+ if (!totpCredential) {
118
+ throw new AuthError('PASSWORD_REQUIRED', 'Full login required', 401);
119
+ }
120
+ if (!ipTrusted) {
121
+ const rateLimitKey = `otp:${ctx.clientKey ?? 'default'}`;
122
+ const rate = this.passwordRateLimit.consume(rateLimitKey);
123
+ if (!rate.allowed) {
124
+ throw new AuthError('RATE_LIMITED', 'Too many attempts', 429);
125
+ }
126
+ if (!otp) {
127
+ throw new AuthError('OTP_REQUIRED', 'OTP code is required', 401);
128
+ }
129
+ if (!this.totpService?.verify(totpCredential.secret, otp)) {
130
+ throw new AuthError('INVALID_OTP', 'Invalid OTP code', 401);
131
+ }
132
+ this.passwordRateLimit.reset(rateLimitKey);
133
+ }
134
+ const seenAt = new Date(this.now()).toISOString();
135
+ await this.store.update((current) => ({
136
+ ...current,
137
+ trustedDevices: current.trustedDevices.map((d) => (d.id === device.id ? { ...d, lastSeenAt: seenAt } : d)),
138
+ ipWhitelist: this.maybeAddIp(current.ipWhitelist, ip, ctx.rememberNetwork)
139
+ }));
140
+ return this.createSession(ip, device.id);
141
+ }
142
+ async setupTotp(sessionId, ip) {
143
+ if (!(await this.validateSession(sessionId, ip))) {
144
+ throw new AuthError('UNAUTHORIZED', 'Not authenticated', 401);
145
+ }
146
+ if (!this.totpService) {
147
+ throw new AuthError('TOTP_NOT_AVAILABLE', 'TOTP service is not configured', 500);
148
+ }
149
+ const state = await this.store.read();
150
+ if (state.totpCredential) {
151
+ throw new AuthError('TOTP_ALREADY_SET', 'TOTP is already enabled', 409);
152
+ }
153
+ return this.totpService.generateSetup('nterminal');
154
+ }
155
+ async activateTotp(sessionId, secret, otp, ip) {
156
+ if (!(await this.validateSession(sessionId, ip))) {
157
+ throw new AuthError('UNAUTHORIZED', 'Not authenticated', 401);
158
+ }
159
+ if (!this.totpService) {
160
+ throw new AuthError('TOTP_NOT_AVAILABLE', 'TOTP service is not configured', 500);
161
+ }
162
+ if (!this.totpService.verify(secret, otp)) {
163
+ throw new AuthError('INVALID_OTP', 'Invalid OTP code', 401);
164
+ }
165
+ const credential = {
166
+ secret,
167
+ algorithm: 'SHA1',
168
+ digits: 6,
169
+ period: 30,
170
+ createdAt: new Date(this.now()).toISOString()
171
+ };
172
+ await this.store.update((current) => {
173
+ if (current.totpCredential) {
174
+ throw new AuthError('TOTP_ALREADY_SET', 'TOTP is already enabled', 409);
175
+ }
176
+ return { ...current, totpCredential: credential };
177
+ }, { flush: 'immediate' });
178
+ }
179
+ async disableTotp(sessionId, ip) {
180
+ if (!(await this.validateSession(sessionId, ip))) {
181
+ throw new AuthError('UNAUTHORIZED', 'Not authenticated', 401);
182
+ }
183
+ await this.store.update((current) => ({ ...current, totpCredential: null }), { flush: 'immediate' });
184
+ }
185
+ async isTotpEnabled() {
186
+ return Boolean((await this.store.read()).totpCredential);
187
+ }
188
+ async validateSession(sessionId, ip, options = {}) {
189
+ const destroy = options.destroy ?? true;
190
+ if (!sessionId) {
191
+ return false;
192
+ }
193
+ const session = this.sessions.get(sessionId);
194
+ if (!session) {
195
+ return false;
196
+ }
197
+ if (session.expiresAtMs <= this.now()) {
198
+ this.sessions.delete(sessionId);
199
+ return false;
200
+ }
201
+ // IP binding: enforced when an IP is supplied for an IP-bound session.
202
+ if (ip !== undefined && session.ip && ip) {
203
+ const normalized = normalizeIp(ip);
204
+ // Accept the originally bound /24 (IPv4) or /48 (IPv6) — strict /32
205
+ // binding broke residential/CGNAT users whose ISP rotates inside the
206
+ // same /24 every few minutes (each rotation destroyed the session,
207
+ // forcing a reauth dance on every WebSocket reconnect or split). The
208
+ // /24 still excludes unrelated networks, and ANY whitelisted CIDR
209
+ // (broader roaming) keeps working through ipMatchesAny below. An
210
+ // unparseable IP fails closed.
211
+ if (normalized && isWithinSessionNetwork(normalized, session.ip)) {
212
+ return true;
213
+ }
214
+ const { ipWhitelist } = await this.store.read();
215
+ if (normalized && ipMatchesAny(normalized, ipWhitelist)) {
216
+ return true;
217
+ }
218
+ if (destroy) {
219
+ this.sessions.delete(sessionId);
220
+ }
221
+ return false;
222
+ }
223
+ return true;
224
+ }
225
+ async getSessionStatus(sessionId, ctx = {}) {
226
+ const state = await this.store.read();
227
+ // Status reads must not revoke: an IP-mismatched poll reports unauthenticated but leaves the
228
+ // session for the protected routes (requireSession) to revoke on an actual mutating request.
229
+ const authenticated = await this.validateSession(sessionId, ctx.ip, { destroy: false });
230
+ const session = sessionId ? this.sessions.get(sessionId) : undefined;
231
+ const ip = normalizeIp(ctx.ip);
232
+ return {
233
+ passwordSet: Boolean(state.passwordCredential),
234
+ authenticated,
235
+ totpEnabled: Boolean(state.totpCredential),
236
+ deviceTrusted: this.findValidDevice(ctx.deviceToken, state.trustedDevices) !== null,
237
+ currentIpWhitelisted: ipMatchesAny(ip, state.ipWhitelist),
238
+ expiresAt: authenticated && session ? new Date(session.expiresAtMs).toISOString() : null
239
+ };
240
+ }
241
+ async requireSession(request) {
242
+ const cookies = request.cookies ?? this.parseCookieHeader(request.headers?.cookie);
243
+ const sessionId = cookies.nterminal_session;
244
+ const ok = await this.validateSession(sessionId, request.ip ?? null);
245
+ return ok && sessionId ? { sessionId } : null;
246
+ }
247
+ async logout(sessionId, deviceToken) {
248
+ if (sessionId) {
249
+ this.sessions.delete(sessionId);
250
+ }
251
+ if (deviceToken) {
252
+ await this.store.update((current) => ({
253
+ ...current,
254
+ trustedDevices: current.trustedDevices.filter((d) => !this.deviceMatchesToken(deviceToken, d))
255
+ }), { flush: 'immediate' });
256
+ }
257
+ }
258
+ async listTrustedDevices(currentDeviceToken) {
259
+ const { trustedDevices } = await this.store.read();
260
+ const currentHash = currentDeviceToken ? this.hashDeviceToken(currentDeviceToken) : null;
261
+ return this.pruneDevices(trustedDevices).map((d) => ({
262
+ id: d.id,
263
+ label: d.label,
264
+ createdAt: d.createdAt,
265
+ lastSeenAt: d.lastSeenAt,
266
+ current: currentHash !== null && this.safeEqual(currentHash, d.tokenHash)
267
+ }));
268
+ }
269
+ async revokeTrustedDevice(id) {
270
+ await this.store.update((current) => ({
271
+ ...current,
272
+ trustedDevices: current.trustedDevices.filter((d) => d.id !== id)
273
+ }), { flush: 'immediate' });
274
+ }
275
+ async listIpRules() {
276
+ return (await this.store.read()).ipWhitelist.map((r) => ({ id: r.id, value: r.value, label: r.label, createdAt: r.createdAt }));
277
+ }
278
+ async addIpRule(value, label) {
279
+ const trimmed = value.trim();
280
+ if (!isValidIpRule(trimmed)) {
281
+ throw new AuthError('INVALID_IP_RULE', 'Invalid IP or CIDR', 400);
282
+ }
283
+ const rule = {
284
+ id: randomUUID(),
285
+ value: trimmed,
286
+ label: label.trim() || trimmed,
287
+ createdAt: new Date(this.now()).toISOString()
288
+ };
289
+ await this.store.update((current) => ({ ...current, ipWhitelist: [...current.ipWhitelist, rule] }), { flush: 'immediate' });
290
+ return { id: rule.id, value: rule.value, label: rule.label, createdAt: rule.createdAt };
291
+ }
292
+ async removeIpRule(id) {
293
+ await this.store.update((current) => ({ ...current, ipWhitelist: current.ipWhitelist.filter((r) => r.id !== id) }), { flush: 'immediate' });
294
+ }
295
+ createSession(ip = null, deviceId = null) {
296
+ // Single active session: any new session supersedes existing ones.
297
+ this.sessions.clear();
298
+ const sessionId = `sess_${crypto.randomBytes(32).toString('base64url')}`;
299
+ const expiresAtMs = this.now() + this.config.sessionTtlMs;
300
+ this.sessions.set(sessionId, { expiresAtMs, ip, deviceId });
301
+ return { sessionId, expiresAt: new Date(expiresAtMs).toISOString() };
302
+ }
303
+ buildTrustedDevice(ctx) {
304
+ const token = `dev_${crypto.randomBytes(32).toString('base64url')}`;
305
+ const timestamp = new Date(this.now()).toISOString();
306
+ const record = {
307
+ id: randomUUID(),
308
+ tokenHash: this.hashDeviceToken(token),
309
+ label: deviceLabel(ctx.userAgent),
310
+ createdAt: timestamp,
311
+ lastSeenAt: timestamp,
312
+ expiresAt: new Date(this.now() + deviceTtlMs).toISOString()
313
+ };
314
+ return { token, record };
315
+ }
316
+ pruneDevices(devices) {
317
+ const nowMs = this.now();
318
+ return devices.filter((d) => Date.parse(d.expiresAt) > nowMs);
319
+ }
320
+ findValidDevice(token, devices) {
321
+ if (!token) {
322
+ return null;
323
+ }
324
+ const hash = this.hashDeviceToken(token);
325
+ const nowMs = this.now();
326
+ for (const device of devices) {
327
+ if (Date.parse(device.expiresAt) > nowMs && this.safeEqual(hash, device.tokenHash)) {
328
+ return device;
329
+ }
330
+ }
331
+ return null;
332
+ }
333
+ deviceMatchesToken(token, device) {
334
+ if (!token) {
335
+ return false;
336
+ }
337
+ return this.safeEqual(this.hashDeviceToken(token), device.tokenHash);
338
+ }
339
+ hashDeviceToken(token) {
340
+ return crypto.createHmac('sha256', this.config.sessionSecret).update(token).digest('base64url');
341
+ }
342
+ maybeAddIp(rules, ip, remember) {
343
+ if (!remember || !ip || ipMatchesAny(ip, rules)) {
344
+ return rules;
345
+ }
346
+ return [
347
+ ...rules,
348
+ { id: randomUUID(), value: ip, label: ip, createdAt: new Date(this.now()).toISOString() }
349
+ ];
350
+ }
351
+ validatePassword(password) {
352
+ if (password.length < 8) {
353
+ throw new AuthError('PASSWORD_TOO_SHORT', 'Password must be at least 8 characters', 400);
354
+ }
355
+ }
356
+ async hashPassword(password, salt) {
357
+ const hash = (await scrypt(`${password}:${this.config.sessionSecret}`, salt, 64));
358
+ return hash.toString('base64url');
359
+ }
360
+ async verifyPassword(password, credential) {
361
+ const candidate = await this.hashPassword(password, credential.salt);
362
+ return this.safeEqual(candidate, credential.hash);
363
+ }
364
+ safeEqual(left, right) {
365
+ const leftBuffer = Buffer.from(left);
366
+ const rightBuffer = Buffer.from(right);
367
+ return leftBuffer.length === rightBuffer.length && crypto.timingSafeEqual(leftBuffer, rightBuffer);
368
+ }
369
+ parseCookieHeader(header) {
370
+ const raw = Array.isArray(header) ? header.join('; ') : header;
371
+ if (!raw) {
372
+ return {};
373
+ }
374
+ return Object.fromEntries(raw
375
+ .split(';')
376
+ .map((part) => part.trim())
377
+ .filter(Boolean)
378
+ .map((part) => {
379
+ const separator = part.indexOf('=');
380
+ if (separator === -1) {
381
+ return [part, ''];
382
+ }
383
+ return [part.slice(0, separator), decodeURIComponent(part.slice(separator + 1))];
384
+ }));
385
+ }
386
+ }
387
+ function deviceLabel(userAgent) {
388
+ if (!userAgent) {
389
+ return 'Unknown device';
390
+ }
391
+ const os = /Windows/i.test(userAgent)
392
+ ? 'Windows'
393
+ : /Mac OS X|Macintosh/i.test(userAgent)
394
+ ? 'macOS'
395
+ : /iPhone|iPad|iOS/i.test(userAgent)
396
+ ? 'iOS'
397
+ : /Android/i.test(userAgent)
398
+ ? 'Android'
399
+ : /Linux/i.test(userAgent)
400
+ ? 'Linux'
401
+ : 'Unknown OS';
402
+ const browser = /Edg/i.test(userAgent)
403
+ ? 'Edge'
404
+ : /OPR|Opera/i.test(userAgent)
405
+ ? 'Opera'
406
+ : /Chrome/i.test(userAgent)
407
+ ? 'Chrome'
408
+ : /Firefox/i.test(userAgent)
409
+ ? 'Firefox'
410
+ : /Safari/i.test(userAgent)
411
+ ? 'Safari'
412
+ : 'Browser';
413
+ return `${browser} / ${os}`;
414
+ }
415
+ //# sourceMappingURL=authService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authService.js","sourceRoot":"","sources":["../../../src/server/auth/authService.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEhG,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACxC,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE7C,MAAM,OAAO,SAAU,SAAQ,KAAK;IAEhB;IAEA;IAHlB,YACkB,IAAY,EAC5B,OAAe,EACC,aAAa,GAAG;QAEhC,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,SAAI,GAAJ,IAAI,CAAQ;QAEZ,eAAU,GAAV,UAAU,CAAM;IAGlC,CAAC;CACF;AA+CD,MAAM,OAAO,WAAW;IAOH;IACA;IAPF,GAAG,CAAe;IAClB,iBAAiB,CAAoB;IACrC,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC5C,WAAW,CAAqB;IAEjD,YACmB,MAAiB,EACjB,KAAgB,EACjC,UAA8B,EAAE;QAFf,WAAM,GAAN,MAAM,CAAW;QACjB,UAAK,GAAL,KAAK,CAAW;QAGjC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QACnC,IAAI,CAAC,iBAAiB;YACpB,OAAO,CAAC,iBAAiB;gBACzB,IAAI,iBAAiB,CAAC;oBACpB,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,MAAM;oBAChB,GAAG,EAAE,IAAI,CAAC,GAAG;iBACd,CAAC,CAAC;QACL,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,MAAmB,EAAE;QACzD,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;YAC7B,MAAM,IAAI,SAAS,CAAC,sBAAsB,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAC;QAC9E,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC1D,MAAM,UAAU,GAA6B;YAC3C,SAAS,EAAE,QAAQ;YACnB,IAAI,EAAE,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC7C,IAAI;YACJ,SAAS,EAAE,SAAS;YACpB,SAAS,EAAE,SAAS;SACrB,CAAC;QACF,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC5E,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CACrB,CAAC,OAAO,EAAE,EAAE;YACV,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;gBAC/B,MAAM,IAAI,SAAS,CAAC,sBAAsB,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO;gBACL,GAAG,OAAO;gBACV,kBAAkB,EAAE,UAAU;gBAC9B,cAAc,EAAE,CAAC,MAAM,CAAC;gBACxB,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,EAAE,GAAG,CAAC,eAAe,CAAC;aAC3E,CAAC;QACJ,CAAC,EACD,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,GAAY,EAAE,MAAmB,EAAE;QAC3E,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,UAAU,GAAG,KAAK,CAAC,kBAAkB,CAAC;QAC5C,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,SAAS,CAAC,kBAAkB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,YAAY,GAAG,YAAY,GAAG,CAAC,SAAS,IAAI,SAAS,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,4BAA4B,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;YACvD,MAAM,IAAI,SAAS,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;QAC5C,IAAI,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;YACnE,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,SAAS,CAAC,aAAa,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAE3C,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC5E,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CACrB,CAAC,OAAO,EAAE,EAAE;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;YACtH,OAAO;gBACL,GAAG,OAAO;gBACV,cAAc,EAAE,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC;gBACpC,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,EAAE,GAAG,CAAC,eAAe,CAAC;aAC3E,CAAC;QACJ,CAAC,EACD,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,GAAuB,EAAE,MAAmB,EAAE;QAChE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,SAAS,CAAC,oBAAoB,EAAE,4BAA4B,EAAE,GAAG,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;QAC5C,MAAM,SAAS,GAAG,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QAEtD,yFAAyF;QACzF,8FAA8F;QAC9F,yEAAyE;QACzE,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,SAAS,CAAC,mBAAmB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,OAAO,GAAG,CAAC,SAAS,IAAI,SAAS,EAAE,CAAC;YACzD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YAC1D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAC;YAChE,CAAC;YACD,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;YACnE,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,SAAS,CAAC,aAAa,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;YAC9D,CAAC;YACD,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAClD,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACpC,GAAG,OAAO;YACV,cAAc,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1G,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,EAAE,GAAG,CAAC,eAAe,CAAC;SAC3E,CAAC,CAAC,CAAC;QACJ,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,SAA6B,EAAE,EAAkB;QAC/D,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,SAAS,CAAC,oBAAoB,EAAE,gCAAgC,EAAE,GAAG,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,IAAI,SAAS,CAAC,kBAAkB,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,SAA6B,EAAE,MAAc,EAAE,GAAW,EAAE,EAAkB;QAC/F,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,SAAS,CAAC,oBAAoB,EAAE,gCAAgC,EAAE,GAAG,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,SAAS,CAAC,aAAa,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,UAAU,GAAyB;YACvC,MAAM;YACN,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE;SAC9C,CAAC;QACF,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CACrB,CAAC,OAAO,EAAE,EAAE;YACV,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;gBAC3B,MAAM,IAAI,SAAS,CAAC,kBAAkB,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAC;YAC1E,CAAC;YACD,OAAO,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC;QACpD,CAAC,EACD,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAA6B,EAAE,EAAkB;QACjE,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAC;QAChE,CAAC;QACD,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvG,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,OAAO,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,SAA6B,EAAE,EAAkB,EAAE,UAAiC,EAAE;QAC1G,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC;QACxC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,uEAAuE;QACvE,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;YACzC,MAAM,UAAU,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;YACnC,oEAAoE;YACpE,qEAAqE;YACrE,mEAAmE;YACnE,qEAAqE;YACrE,kEAAkE;YAClE,iEAAiE;YACjE,+BAA+B;YAC/B,IAAI,UAAU,IAAI,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;gBACjE,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAChD,IAAI,UAAU,IAAI,YAAY,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;gBACxD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAClC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,SAA6B,EAC7B,MAAmF,EAAE;QAErF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,6FAA6F;QAC7F,6FAA6F;QAC7F,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACxF,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrE,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO;YACL,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC;YAC9C,aAAa;YACb,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;YAC1C,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,IAAI;YACnF,oBAAoB,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC;YACzD,SAAS,EAAE,aAAa,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;SACzF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAIpB;QACC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACnF,MAAM,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QAC5C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;QACrE,OAAO,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAA6B,EAAE,WAA2B;QACrE,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CACrB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACZ,GAAG,OAAO;gBACV,cAAc,EAAE,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;aAC/F,CAAC,EACF,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,kBAAkC;QACzD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACnD,MAAM,WAAW,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACzF,OAAO,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnD,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,OAAO,EAAE,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC;SAC1E,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,EAAU;QAClC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CACrB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACZ,GAAG,OAAO;YACV,cAAc,EAAE,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;SAClE,CAAC,EACF,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAClI,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,KAAa,EAAE,KAAa;QAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,SAAS,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,IAAI,GAAiB;YACzB,EAAE,EAAE,UAAU,EAAE;YAChB,KAAK,EAAE,OAAO;YACd,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,OAAO;YAC9B,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE;SAC9C,CAAC;QACF,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CACrB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,EAC1E,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IAC1F,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAU;QAC3B,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CACrB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAC1F,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAC;IACJ,CAAC;IAEO,aAAa,CAAC,KAAoB,IAAI,EAAE,WAA0B,IAAI;QAC5E,mEAAmE;QACnE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,QAAQ,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACzE,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QAC1D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IACvE,CAAC;IAEO,kBAAkB,CAAC,GAAgB;QACzC,MAAM,KAAK,GAAG,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpE,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACrD,MAAM,MAAM,GAAwB;YAClC,EAAE,EAAE,UAAU,EAAE;YAChB,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;YACtC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC;YACjC,SAAS,EAAE,SAAS;YACpB,UAAU,EAAE,SAAS;YACrB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,CAAC,WAAW,EAAE;SAC5D,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;IAEO,YAAY,CAAC,OAA8B;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,CAAC;IAChE,CAAC;IAEO,eAAe,CAAC,KAAgC,EAAE,OAA8B;QACtF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnF,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,kBAAkB,CAAC,KAAgC,EAAE,MAA2B;QACtF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACvE,CAAC;IAEO,eAAe,CAAC,KAAa;QACnC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAClG,CAAC;IAEO,UAAU,CAAC,KAAqB,EAAE,EAAiB,EAAE,QAA6B;QACxF,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,IAAI,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;YAChD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO;YACL,GAAG,KAAK;YACR,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE;SAC1F,CAAC;IACJ,CAAC;IAEO,gBAAgB,CAAC,QAAgB;QACvC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,SAAS,CAAC,oBAAoB,EAAE,wCAAwC,EAAE,GAAG,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,IAAY;QACvD,MAAM,IAAI,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAW,CAAC;QAC5F,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACpC,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,UAAoC;QACjF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QACrE,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAEO,SAAS,CAAC,IAAY,EAAE,KAAa;QAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,OAAO,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,IAAI,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACrG,CAAC;IAEO,iBAAiB,CAAC,MAAqC;QAC7D,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,MAAM,CAAC,WAAW,CACvB,GAAG;aACA,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACZ,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;gBACrB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnF,CAAC,CAAC,CACL,CAAC;IACJ,CAAC;CACF;AAED,SAAS,WAAW,CAAC,SAAoC;IACvD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;QACnC,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC;YACrC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC;gBAClC,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;oBAC1B,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;wBACxB,CAAC,CAAC,OAAO;wBACT,CAAC,CAAC,YAAY,CAAC;IACzB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;QACpC,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;YAC5B,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;gBACzB,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;oBAC1B,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;wBACzB,CAAC,CAAC,QAAQ;wBACV,CAAC,CAAC,SAAS,CAAC;IACtB,OAAO,GAAG,OAAO,MAAM,EAAE,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { FastifyReply } from 'fastify';
2
+ import type { AppConfig } from '../config.js';
3
+ export declare const cookieNames: {
4
+ readonly session: "nterminal_session";
5
+ readonly device: "nterminal_device";
6
+ };
7
+ export declare function authCookieOptions(config: AppConfig, maxAgeSeconds?: number): import("@fastify/cookie").CookieSerializeOptions;
8
+ export declare function setSessionCookie(reply: FastifyReply, config: AppConfig, sessionId: string): void;
9
+ export declare function setDeviceCookie(reply: FastifyReply, config: AppConfig, token: string): void;
10
+ export declare function clearSessionCookie(reply: FastifyReply, config: AppConfig): void;
11
+ export declare function clearAuthCookies(reply: FastifyReply, config: AppConfig): void;