imperium-crawl 1.5.3 → 2.1.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 (125) hide show
  1. package/README.md +49 -34
  2. package/dist/constants.d.ts +2 -1
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +3 -1
  5. package/dist/constants.js.map +1 -1
  6. package/dist/network/interceptor.d.ts +19 -0
  7. package/dist/network/interceptor.d.ts.map +1 -0
  8. package/dist/network/interceptor.js +82 -0
  9. package/dist/network/interceptor.js.map +1 -0
  10. package/dist/network/types.d.ts +27 -0
  11. package/dist/network/types.d.ts.map +1 -0
  12. package/dist/network/types.js +2 -0
  13. package/dist/network/types.js.map +1 -0
  14. package/dist/recipes/index.d.ts.map +1 -1
  15. package/dist/recipes/index.js +6 -0
  16. package/dist/recipes/index.js.map +1 -1
  17. package/dist/recipes/influencer-competitor-spy.json +14 -0
  18. package/dist/recipes/influencer-hashtag-scout.json +14 -0
  19. package/dist/recipes/influencer-niche-discovery.json +14 -0
  20. package/dist/security/action-policy.d.ts +26 -0
  21. package/dist/security/action-policy.d.ts.map +1 -0
  22. package/dist/security/action-policy.js +136 -0
  23. package/dist/security/action-policy.js.map +1 -0
  24. package/dist/security/auth-vault.d.ts +49 -0
  25. package/dist/security/auth-vault.d.ts.map +1 -0
  26. package/dist/security/auth-vault.js +133 -0
  27. package/dist/security/auth-vault.js.map +1 -0
  28. package/dist/security/domain-filter.d.ts +19 -0
  29. package/dist/security/domain-filter.d.ts.map +1 -0
  30. package/dist/security/domain-filter.js +114 -0
  31. package/dist/security/domain-filter.js.map +1 -0
  32. package/dist/security/types.d.ts +19 -0
  33. package/dist/security/types.d.ts.map +1 -0
  34. package/dist/security/types.js +2 -0
  35. package/dist/security/types.js.map +1 -0
  36. package/dist/sessions/encryption.d.ts +37 -0
  37. package/dist/sessions/encryption.d.ts.map +1 -0
  38. package/dist/sessions/encryption.js +108 -0
  39. package/dist/sessions/encryption.js.map +1 -0
  40. package/dist/sessions/index.d.ts +1 -0
  41. package/dist/sessions/index.d.ts.map +1 -1
  42. package/dist/sessions/index.js +1 -0
  43. package/dist/sessions/index.js.map +1 -1
  44. package/dist/sessions/manager.d.ts +3 -0
  45. package/dist/sessions/manager.d.ts.map +1 -1
  46. package/dist/sessions/manager.js +28 -2
  47. package/dist/sessions/manager.js.map +1 -1
  48. package/dist/skills/manager.d.ts +11 -2
  49. package/dist/skills/manager.d.ts.map +1 -1
  50. package/dist/skills/manager.js.map +1 -1
  51. package/dist/snapshot/annotator.d.ts +21 -0
  52. package/dist/snapshot/annotator.d.ts.map +1 -0
  53. package/dist/snapshot/annotator.js +152 -0
  54. package/dist/snapshot/annotator.js.map +1 -0
  55. package/dist/snapshot/boundary.d.ts +7 -0
  56. package/dist/snapshot/boundary.d.ts.map +1 -0
  57. package/dist/snapshot/boundary.js +12 -0
  58. package/dist/snapshot/boundary.js.map +1 -0
  59. package/dist/snapshot/differ.d.ts +40 -0
  60. package/dist/snapshot/differ.d.ts.map +1 -0
  61. package/dist/snapshot/differ.js +194 -0
  62. package/dist/snapshot/differ.js.map +1 -0
  63. package/dist/snapshot/extractor.d.ts +27 -0
  64. package/dist/snapshot/extractor.d.ts.map +1 -0
  65. package/dist/snapshot/extractor.js +265 -0
  66. package/dist/snapshot/extractor.js.map +1 -0
  67. package/dist/snapshot/index.d.ts +8 -0
  68. package/dist/snapshot/index.d.ts.map +1 -0
  69. package/dist/snapshot/index.js +6 -0
  70. package/dist/snapshot/index.js.map +1 -0
  71. package/dist/snapshot/store.d.ts +28 -0
  72. package/dist/snapshot/store.d.ts.map +1 -0
  73. package/dist/snapshot/store.js +65 -0
  74. package/dist/snapshot/store.js.map +1 -0
  75. package/dist/snapshot/types.d.ts +42 -0
  76. package/dist/snapshot/types.d.ts.map +1 -0
  77. package/dist/snapshot/types.js +2 -0
  78. package/dist/snapshot/types.js.map +1 -0
  79. package/dist/social/ai-fallback.d.ts +22 -0
  80. package/dist/social/ai-fallback.d.ts.map +1 -0
  81. package/dist/social/ai-fallback.js +137 -0
  82. package/dist/social/ai-fallback.js.map +1 -0
  83. package/dist/social/parsers.d.ts +28 -0
  84. package/dist/social/parsers.d.ts.map +1 -0
  85. package/dist/social/parsers.js +146 -0
  86. package/dist/social/parsers.js.map +1 -0
  87. package/dist/social/types.d.ts +55 -0
  88. package/dist/social/types.d.ts.map +1 -0
  89. package/dist/social/types.js +5 -0
  90. package/dist/social/types.js.map +1 -0
  91. package/dist/social/whisper.d.ts +29 -0
  92. package/dist/social/whisper.d.ts.map +1 -0
  93. package/dist/social/whisper.js +88 -0
  94. package/dist/social/whisper.js.map +1 -0
  95. package/dist/tools/index.d.ts.map +1 -1
  96. package/dist/tools/index.js +7 -0
  97. package/dist/tools/index.js.map +1 -1
  98. package/dist/tools/interact.d.ts +194 -5
  99. package/dist/tools/interact.d.ts.map +1 -1
  100. package/dist/tools/interact.js +355 -20
  101. package/dist/tools/interact.js.map +1 -1
  102. package/dist/tools/manifest.d.ts.map +1 -1
  103. package/dist/tools/manifest.js +9 -0
  104. package/dist/tools/manifest.js.map +1 -1
  105. package/dist/tools/reddit.d.ts +36 -0
  106. package/dist/tools/reddit.d.ts.map +1 -0
  107. package/dist/tools/reddit.js +190 -0
  108. package/dist/tools/reddit.js.map +1 -0
  109. package/dist/tools/run-skill.d.ts +18 -0
  110. package/dist/tools/run-skill.d.ts.map +1 -1
  111. package/dist/tools/run-skill.js +681 -0
  112. package/dist/tools/run-skill.js.map +1 -1
  113. package/dist/tools/snapshot.d.ts +53 -0
  114. package/dist/tools/snapshot.d.ts.map +1 -0
  115. package/dist/tools/snapshot.js +160 -0
  116. package/dist/tools/snapshot.js.map +1 -0
  117. package/dist/tools/tiktok.d.ts +30 -0
  118. package/dist/tools/tiktok.d.ts.map +1 -0
  119. package/dist/tools/tiktok.js +246 -0
  120. package/dist/tools/tiktok.js.map +1 -0
  121. package/dist/tools/youtube.d.ts +33 -0
  122. package/dist/tools/youtube.d.ts.map +1 -0
  123. package/dist/tools/youtube.js +489 -0
  124. package/dist/tools/youtube.js.map +1 -0
  125. package/package.json +1 -1
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Auth Vault — Encrypted credential storage for login automation.
3
+ *
4
+ * Stores login profiles (URL, username, password, form selectors)
5
+ * encrypted on disk. Profiles are decrypted on-demand for login flows.
6
+ */
7
+ export interface AuthProfile {
8
+ name: string;
9
+ url: string;
10
+ username: string;
11
+ password: string;
12
+ selectors: {
13
+ username: string;
14
+ password: string;
15
+ submit: string;
16
+ };
17
+ lastLogin?: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ }
21
+ export interface AuthProfileMeta {
22
+ name: string;
23
+ url: string;
24
+ username: string;
25
+ lastLogin?: string;
26
+ createdAt: string;
27
+ updatedAt: string;
28
+ }
29
+ /**
30
+ * Save an auth profile (encrypted on disk).
31
+ */
32
+ export declare function saveAuthProfile(profile: Omit<AuthProfile, "createdAt" | "updatedAt">): Promise<void>;
33
+ /**
34
+ * Get a decrypted auth profile by name.
35
+ */
36
+ export declare function getAuthProfile(name: string): Promise<AuthProfile | null>;
37
+ /**
38
+ * List all auth profiles (meta only — no passwords).
39
+ */
40
+ export declare function listAuthProfiles(): Promise<AuthProfileMeta[]>;
41
+ /**
42
+ * Delete an auth profile.
43
+ */
44
+ export declare function deleteAuthProfile(name: string): Promise<boolean>;
45
+ /**
46
+ * Update the lastLogin timestamp for a profile.
47
+ */
48
+ export declare function updateLastLogin(name: string): Promise<void>;
49
+ //# sourceMappingURL=auth-vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-vault.d.ts","sourceRoot":"","sources":["../../src/security/auth-vault.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAaD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B1G;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAgB9E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAiCnE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOtE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjE"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Auth Vault — Encrypted credential storage for login automation.
3
+ *
4
+ * Stores login profiles (URL, username, password, form selectors)
5
+ * encrypted on disk. Profiles are decrypted on-demand for login flows.
6
+ */
7
+ import fs from "node:fs/promises";
8
+ import path from "node:path";
9
+ import os from "node:os";
10
+ import { SKILLS_DIR_NAME } from "../constants.js";
11
+ import { encryptData, decryptData, isEncryptedPayload, ensureEncryptionKey } from "../sessions/encryption.js";
12
+ const AUTH_SUBDIR = "auth";
13
+ const PROFILE_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;
14
+ function getAuthDir() {
15
+ return path.join(os.homedir(), SKILLS_DIR_NAME, AUTH_SUBDIR);
16
+ }
17
+ function profilePath(name) {
18
+ if (!PROFILE_NAME_REGEX.test(name)) {
19
+ throw new Error(`Invalid profile name: '${name}'. Use only alphanumeric, underscore, and hyphen.`);
20
+ }
21
+ return path.join(getAuthDir(), `${name}.json`);
22
+ }
23
+ /**
24
+ * Save an auth profile (encrypted on disk).
25
+ */
26
+ export async function saveAuthProfile(profile) {
27
+ const key = await ensureEncryptionKey();
28
+ if (!key) {
29
+ throw new Error("Encryption key required for auth vault. Set SESSION_ENCRYPTION_KEY env var or run 'imperium-crawl setup'.");
30
+ }
31
+ const dir = getAuthDir();
32
+ await fs.mkdir(dir, { recursive: true });
33
+ // Load existing for createdAt preservation
34
+ let createdAt = new Date().toISOString();
35
+ try {
36
+ const existing = await getAuthProfile(profile.name);
37
+ if (existing)
38
+ createdAt = existing.createdAt;
39
+ }
40
+ catch {
41
+ // New profile
42
+ }
43
+ const fullProfile = {
44
+ ...profile,
45
+ createdAt,
46
+ updatedAt: new Date().toISOString(),
47
+ };
48
+ const encrypted = encryptData(JSON.stringify(fullProfile), key);
49
+ const filePath = profilePath(profile.name);
50
+ const tmpPath = filePath + ".tmp";
51
+ await fs.writeFile(tmpPath, JSON.stringify(encrypted, null, 2), { encoding: "utf-8", mode: 0o600 });
52
+ await fs.rename(tmpPath, filePath);
53
+ }
54
+ /**
55
+ * Get a decrypted auth profile by name.
56
+ */
57
+ export async function getAuthProfile(name) {
58
+ const key = await ensureEncryptionKey();
59
+ if (!key)
60
+ return null;
61
+ try {
62
+ const data = await fs.readFile(profilePath(name), "utf-8");
63
+ const parsed = JSON.parse(data);
64
+ if (isEncryptedPayload(parsed)) {
65
+ return JSON.parse(decryptData(parsed, key));
66
+ }
67
+ return parsed;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ /**
74
+ * List all auth profiles (meta only — no passwords).
75
+ */
76
+ export async function listAuthProfiles() {
77
+ const dir = getAuthDir();
78
+ const key = await ensureEncryptionKey();
79
+ try {
80
+ const files = await fs.readdir(dir);
81
+ const profiles = [];
82
+ for (const file of files) {
83
+ if (!file.endsWith(".json") || file.endsWith(".tmp.json"))
84
+ continue;
85
+ const name = file.replace(/\.json$/, "");
86
+ try {
87
+ const profile = key ? await getAuthProfile(name) : null;
88
+ if (profile) {
89
+ profiles.push({
90
+ name: profile.name,
91
+ url: profile.url,
92
+ username: profile.username,
93
+ lastLogin: profile.lastLogin,
94
+ createdAt: profile.createdAt,
95
+ updatedAt: profile.updatedAt,
96
+ });
97
+ }
98
+ }
99
+ catch {
100
+ // Skip unreadable profiles
101
+ }
102
+ }
103
+ return profiles;
104
+ }
105
+ catch {
106
+ return [];
107
+ }
108
+ }
109
+ /**
110
+ * Delete an auth profile.
111
+ */
112
+ export async function deleteAuthProfile(name) {
113
+ try {
114
+ await fs.unlink(profilePath(name));
115
+ return true;
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ }
121
+ /**
122
+ * Update the lastLogin timestamp for a profile.
123
+ */
124
+ export async function updateLastLogin(name) {
125
+ const profile = await getAuthProfile(name);
126
+ if (!profile)
127
+ return;
128
+ await saveAuthProfile({
129
+ ...profile,
130
+ lastLogin: new Date().toISOString(),
131
+ });
132
+ }
133
+ //# sourceMappingURL=auth-vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-vault.js","sourceRoot":"","sources":["../../src/security/auth-vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Domain Filter — Security sandbox for browser actions.
3
+ *
4
+ * Blocks requests to non-allowed domains via page.route().
5
+ * Also patches WebSocket/EventSource/sendBeacon to prevent data exfiltration.
6
+ */
7
+ type BrowserContext = import("rebrowser-playwright").BrowserContext;
8
+ /**
9
+ * Check if a hostname matches any of the allowed patterns.
10
+ * Supports exact match and wildcard (*.example.com).
11
+ */
12
+ export declare function isDomainAllowed(hostname: string, patterns: string[]): boolean;
13
+ /**
14
+ * Install domain filter on a browser context.
15
+ * Blocks all requests to non-allowed domains + patches WebSocket/EventSource.
16
+ */
17
+ export declare function installDomainFilter(context: BrowserContext, allowedDomains: string[]): Promise<void>;
18
+ export {};
19
+ //# sourceMappingURL=domain-filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-filter.d.ts","sourceRoot":"","sources":["../../src/security/domain-filter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,KAAK,cAAc,GAAG,OAAO,sBAAsB,EAAE,cAAc,CAAC;AAEpE;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAa7E;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,cAAc,EACvB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CAoFf"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Domain Filter — Security sandbox for browser actions.
3
+ *
4
+ * Blocks requests to non-allowed domains via page.route().
5
+ * Also patches WebSocket/EventSource/sendBeacon to prevent data exfiltration.
6
+ */
7
+ /**
8
+ * Check if a hostname matches any of the allowed patterns.
9
+ * Supports exact match and wildcard (*.example.com).
10
+ */
11
+ export function isDomainAllowed(hostname, patterns) {
12
+ const lower = hostname.toLowerCase();
13
+ for (const pattern of patterns) {
14
+ const p = pattern.toLowerCase();
15
+ if (p === lower)
16
+ return true;
17
+ if (p.startsWith("*.")) {
18
+ const suffix = p.slice(2);
19
+ if (lower === suffix || lower.endsWith(`.${suffix}`))
20
+ return true;
21
+ }
22
+ }
23
+ return false;
24
+ }
25
+ /**
26
+ * Install domain filter on a browser context.
27
+ * Blocks all requests to non-allowed domains + patches WebSocket/EventSource.
28
+ */
29
+ export async function installDomainFilter(context, allowedDomains) {
30
+ if (!allowedDomains.length)
31
+ return;
32
+ // Block HTTP requests to non-allowed domains
33
+ await context.route("**/*", (route) => {
34
+ try {
35
+ const url = new URL(route.request().url());
36
+ if (isDomainAllowed(url.hostname, allowedDomains)) {
37
+ route.continue();
38
+ }
39
+ else {
40
+ route.abort("blockedbyclient");
41
+ }
42
+ }
43
+ catch {
44
+ // Invalid URL — allow (probably internal)
45
+ route.continue();
46
+ }
47
+ });
48
+ // Patch WebSocket/EventSource/sendBeacon in page context
49
+ const initScript = `
50
+ (function() {
51
+ const allowedDomains = ${JSON.stringify(allowedDomains)};
52
+
53
+ function isDomainAllowed(hostname) {
54
+ const lower = hostname.toLowerCase();
55
+ for (const pattern of allowedDomains) {
56
+ const p = pattern.toLowerCase();
57
+ if (p === lower) return true;
58
+ if (p.startsWith('*.')) {
59
+ const suffix = p.slice(2);
60
+ if (lower === suffix || lower.endsWith('.' + suffix)) return true;
61
+ }
62
+ }
63
+ return false;
64
+ }
65
+
66
+ function checkUrl(urlStr) {
67
+ try {
68
+ const url = new URL(urlStr, window.location.href);
69
+ return isDomainAllowed(url.hostname);
70
+ } catch {
71
+ return false;
72
+ }
73
+ }
74
+
75
+ // Patch WebSocket
76
+ const OrigWebSocket = window.WebSocket;
77
+ window.WebSocket = function(url, protocols) {
78
+ if (!checkUrl(url)) {
79
+ console.warn('[imperium-crawl] Blocked WebSocket to:', url);
80
+ throw new DOMException('Blocked by domain filter', 'SecurityError');
81
+ }
82
+ return new OrigWebSocket(url, protocols);
83
+ };
84
+ window.WebSocket.prototype = OrigWebSocket.prototype;
85
+
86
+ // Patch EventSource
87
+ const OrigEventSource = window.EventSource;
88
+ if (OrigEventSource) {
89
+ window.EventSource = function(url, opts) {
90
+ if (!checkUrl(url)) {
91
+ console.warn('[imperium-crawl] Blocked EventSource to:', url);
92
+ throw new DOMException('Blocked by domain filter', 'SecurityError');
93
+ }
94
+ return new OrigEventSource(url, opts);
95
+ };
96
+ window.EventSource.prototype = OrigEventSource.prototype;
97
+ }
98
+
99
+ // Patch sendBeacon
100
+ const origSendBeacon = navigator.sendBeacon?.bind(navigator);
101
+ if (origSendBeacon) {
102
+ navigator.sendBeacon = function(url, data) {
103
+ if (!checkUrl(url)) {
104
+ console.warn('[imperium-crawl] Blocked sendBeacon to:', url);
105
+ return false;
106
+ }
107
+ return origSendBeacon(url, data);
108
+ };
109
+ }
110
+ })();
111
+ `;
112
+ await context.addInitScript(initScript);
113
+ }
114
+ //# sourceMappingURL=domain-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-filter.js","sourceRoot":"","sources":["../../src/security/domain-filter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,QAAkB;IAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAErC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC;QAC7B,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC;gBAAE,OAAO,IAAI,CAAC;QACpE,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAuB,EACvB,cAAwB;IAExB,IAAI,CAAC,cAAc,CAAC,MAAM;QAAE,OAAO;IAEnC,6CAA6C;IAC7C,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;YAC3C,IAAI,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,CAAC;gBAClD,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;YAC1C,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,yDAAyD;IACzD,MAAM,UAAU,GAAG;;+BAEU,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4D1D,CAAC;IAEF,MAAM,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,19 @@
1
+ /** Action policy decision */
2
+ export type PolicyDecision = "allow" | "deny" | "confirm";
3
+ /** Action policy configuration */
4
+ export interface ActionPolicyConfig {
5
+ /** Default decision for uncategorized actions */
6
+ default: "allow" | "deny";
7
+ /** Allowed categories override default */
8
+ allow?: string[];
9
+ /** Denied categories override default and allow */
10
+ deny?: string[];
11
+ /** Categories requiring explicit confirmation */
12
+ confirm?: string[];
13
+ }
14
+ /** Domain filter patterns */
15
+ export interface DomainFilterConfig {
16
+ /** Allowed domain patterns (exact or wildcard *.example.com) */
17
+ allowed_domains: string[];
18
+ }
19
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/security/types.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1D,kCAAkC;AAClC,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,6BAA6B;AAC7B,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/security/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Session Encryption — AES-256-GCM with scrypt key derivation.
3
+ *
4
+ * Auto-encrypts session files when SESSION_ENCRYPTION_KEY env var is set.
5
+ * Uses Node.js crypto module only, zero deps.
6
+ */
7
+ export interface EncryptedPayload {
8
+ version: 1;
9
+ algorithm: "aes-256-gcm";
10
+ iv: string;
11
+ authTag: string;
12
+ ciphertext: string;
13
+ salt: string;
14
+ }
15
+ /**
16
+ * Encrypt plaintext with AES-256-GCM.
17
+ */
18
+ export declare function encryptData(plaintext: string, userKey: string): EncryptedPayload;
19
+ /**
20
+ * Decrypt an encrypted payload.
21
+ */
22
+ export declare function decryptData(payload: EncryptedPayload, userKey: string): string;
23
+ /**
24
+ * Check if an object looks like an encrypted payload.
25
+ */
26
+ export declare function isEncryptedPayload(obj: unknown): obj is EncryptedPayload;
27
+ /**
28
+ * Get encryption key from env var or auto-generated key file.
29
+ * Returns undefined if no key is configured and no key file exists.
30
+ */
31
+ export declare function ensureEncryptionKey(): Promise<string | undefined>;
32
+ /**
33
+ * Generate a new encryption key and save to file.
34
+ * Only call this explicitly (e.g. from setup wizard).
35
+ */
36
+ export declare function generateEncryptionKey(): Promise<string>;
37
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/sessions/encryption.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoBH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,aAAa,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AASD;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAoBhF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAc9E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,gBAAgB,CAWxE;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAcvE;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CAS7D"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Session Encryption — AES-256-GCM with scrypt key derivation.
3
+ *
4
+ * Auto-encrypts session files when SESSION_ENCRYPTION_KEY env var is set.
5
+ * Uses Node.js crypto module only, zero deps.
6
+ */
7
+ import { randomBytes, createCipheriv, createDecipheriv, scryptSync, } from "node:crypto";
8
+ import fs from "node:fs/promises";
9
+ import path from "node:path";
10
+ import os from "node:os";
11
+ import { SKILLS_DIR_NAME } from "../constants.js";
12
+ const ALGORITHM = "aes-256-gcm";
13
+ const KEY_LENGTH = 32;
14
+ const IV_LENGTH = 12;
15
+ const SALT_LENGTH = 16;
16
+ const AUTH_TAG_LENGTH = 16;
17
+ const ENCRYPTION_KEY_FILENAME = "encryption.key";
18
+ /**
19
+ * Derive a 256-bit key from user password using scrypt.
20
+ */
21
+ function deriveKey(userKey, salt) {
22
+ return scryptSync(userKey, salt, KEY_LENGTH);
23
+ }
24
+ /**
25
+ * Encrypt plaintext with AES-256-GCM.
26
+ */
27
+ export function encryptData(plaintext, userKey) {
28
+ const salt = randomBytes(SALT_LENGTH);
29
+ const key = deriveKey(userKey, salt);
30
+ const iv = randomBytes(IV_LENGTH);
31
+ const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
32
+ const encrypted = Buffer.concat([
33
+ cipher.update(plaintext, "utf-8"),
34
+ cipher.final(),
35
+ ]);
36
+ const authTag = cipher.getAuthTag();
37
+ return {
38
+ version: 1,
39
+ algorithm: ALGORITHM,
40
+ iv: iv.toString("hex"),
41
+ authTag: authTag.toString("hex"),
42
+ ciphertext: encrypted.toString("hex"),
43
+ salt: salt.toString("hex"),
44
+ };
45
+ }
46
+ /**
47
+ * Decrypt an encrypted payload.
48
+ */
49
+ export function decryptData(payload, userKey) {
50
+ const salt = Buffer.from(payload.salt, "hex");
51
+ const key = deriveKey(userKey, salt);
52
+ const iv = Buffer.from(payload.iv, "hex");
53
+ const authTag = Buffer.from(payload.authTag, "hex");
54
+ const ciphertext = Buffer.from(payload.ciphertext, "hex");
55
+ const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
56
+ decipher.setAuthTag(authTag);
57
+ return Buffer.concat([
58
+ decipher.update(ciphertext),
59
+ decipher.final(),
60
+ ]).toString("utf-8");
61
+ }
62
+ /**
63
+ * Check if an object looks like an encrypted payload.
64
+ */
65
+ export function isEncryptedPayload(obj) {
66
+ if (!obj || typeof obj !== "object")
67
+ return false;
68
+ const o = obj;
69
+ return (o.version === 1 &&
70
+ o.algorithm === ALGORITHM &&
71
+ typeof o.iv === "string" &&
72
+ typeof o.authTag === "string" &&
73
+ typeof o.ciphertext === "string" &&
74
+ typeof o.salt === "string");
75
+ }
76
+ /**
77
+ * Get encryption key from env var or auto-generated key file.
78
+ * Returns undefined if no key is configured and no key file exists.
79
+ */
80
+ export async function ensureEncryptionKey() {
81
+ // Env var takes priority
82
+ const envKey = process.env.SESSION_ENCRYPTION_KEY?.trim();
83
+ if (envKey)
84
+ return envKey;
85
+ // Check for existing key file
86
+ const keyPath = path.join(os.homedir(), SKILLS_DIR_NAME, ENCRYPTION_KEY_FILENAME);
87
+ try {
88
+ const key = await fs.readFile(keyPath, "utf-8");
89
+ return key.trim();
90
+ }
91
+ catch {
92
+ // No key file — return undefined (encryption not configured)
93
+ return undefined;
94
+ }
95
+ }
96
+ /**
97
+ * Generate a new encryption key and save to file.
98
+ * Only call this explicitly (e.g. from setup wizard).
99
+ */
100
+ export async function generateEncryptionKey() {
101
+ const key = randomBytes(32).toString("hex");
102
+ const dir = path.join(os.homedir(), SKILLS_DIR_NAME);
103
+ const keyPath = path.join(dir, ENCRYPTION_KEY_FILENAME);
104
+ await fs.mkdir(dir, { recursive: true });
105
+ await fs.writeFile(keyPath, key, { encoding: "utf-8", mode: 0o600 });
106
+ return key;
107
+ }
108
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/sessions/encryption.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export type { StoredSession, StoredCookie } from "./types.js";
2
2
  export { SessionManager, getSessionManager, resetSessionManager } from "./manager.js";
3
+ export { encryptData, decryptData, isEncryptedPayload, ensureEncryptionKey, generateEncryptionKey, } from "./encryption.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export { SessionManager, getSessionManager, resetSessionManager } from "./manager.js";
2
+ export { encryptData, decryptData, isEncryptedPayload, ensureEncryptionKey, generateEncryptionKey, } from "./encryption.js";
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
@@ -2,7 +2,10 @@ import type { StoredSession, StoredCookie } from "./types.js";
2
2
  export declare class SessionManager {
3
3
  private cache;
4
4
  private dir;
5
+ private encryptionKey;
6
+ private keyLoaded;
5
7
  constructor(dir?: string);
8
+ private getEncryptionKey;
6
9
  private sessionPath;
7
10
  save(id: string, cookies: StoredCookie[], url: string): Promise<void>;
8
11
  load(id: string): Promise<StoredSession | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/sessions/manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9D,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,GAAG,CAAS;gBAER,GAAG,CAAC,EAAE,MAAM;IAIxB,OAAO,CAAC,WAAW;IAMb,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBrE,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAwB/C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjC,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAUhC;AAMD,wBAAgB,iBAAiB,IAAI,cAAc,CAKlD;AAED,oCAAoC;AACpC,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/sessions/manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,SAAS,CAAS;gBAEd,GAAG,CAAC,EAAE,MAAM;YAIV,gBAAgB;IAQ9B,OAAO,CAAC,WAAW;IAMb,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BrE,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAqC/C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjC,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAUhC;AAMD,wBAAgB,iBAAiB,IAAI,cAAc,CAKlD;AAED,oCAAoC;AACpC,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -1,12 +1,22 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { getSessionsDir } from "../config.js";
4
+ import { encryptData, decryptData, isEncryptedPayload, ensureEncryptionKey } from "./encryption.js";
4
5
  export class SessionManager {
5
6
  cache = new Map();
6
7
  dir;
8
+ encryptionKey;
9
+ keyLoaded = false;
7
10
  constructor(dir) {
8
11
  this.dir = dir ?? getSessionsDir();
9
12
  }
13
+ async getEncryptionKey() {
14
+ if (!this.keyLoaded) {
15
+ this.encryptionKey = await ensureEncryptionKey();
16
+ this.keyLoaded = true;
17
+ }
18
+ return this.encryptionKey;
19
+ }
10
20
  sessionPath(id) {
11
21
  // Sanitize id to prevent path traversal
12
22
  const safe = id.replace(/[^a-zA-Z0-9_\-]/g, "_");
@@ -26,7 +36,11 @@ export class SessionManager {
26
36
  await fs.mkdir(this.dir, { recursive: true });
27
37
  const filePath = this.sessionPath(id);
28
38
  const tmpPath = filePath + ".tmp";
29
- await fs.writeFile(tmpPath, JSON.stringify(session, null, 2), "utf-8");
39
+ const key = await this.getEncryptionKey();
40
+ const content = key
41
+ ? JSON.stringify(encryptData(JSON.stringify(session), key), null, 2)
42
+ : JSON.stringify(session, null, 2);
43
+ await fs.writeFile(tmpPath, content, "utf-8");
30
44
  await fs.rename(tmpPath, filePath);
31
45
  }
32
46
  async load(id) {
@@ -34,7 +48,19 @@ export class SessionManager {
34
48
  return this.cache.get(id);
35
49
  try {
36
50
  const data = await fs.readFile(this.sessionPath(id), "utf-8");
37
- const session = JSON.parse(data);
51
+ const parsed = JSON.parse(data);
52
+ let session;
53
+ if (isEncryptedPayload(parsed)) {
54
+ const key = await this.getEncryptionKey();
55
+ if (!key) {
56
+ console.error("[sessions] Encrypted session found but no encryption key configured");
57
+ return null;
58
+ }
59
+ session = JSON.parse(decryptData(parsed, key));
60
+ }
61
+ else {
62
+ session = parsed;
63
+ }
38
64
  this.cache.set(id, session);
39
65
  return session;
40
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/sessions/manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/sessions/manager.ts"],"names":[],"mappings":"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"}