@phi-code-admin/camofox-browser 1.0.0 → 1.0.2
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/AGENTS.md +571 -571
- package/Dockerfile +86 -86
- package/LICENSE +21 -21
- package/README.md +691 -691
- package/camofox.config.json +10 -10
- package/lib/auth.js +134 -134
- package/lib/camoufox-executable.js +189 -189
- package/lib/config.js +153 -153
- package/lib/cookies.js +119 -119
- package/lib/downloads.js +168 -168
- package/lib/extract.js +74 -74
- package/lib/fly.js +54 -54
- package/lib/images.js +88 -88
- package/lib/inflight.js +16 -16
- package/lib/launcher.js +47 -47
- package/lib/macros.js +31 -31
- package/lib/metrics.js +184 -184
- package/lib/openapi.js +105 -105
- package/lib/persistence.js +89 -89
- package/lib/plugins.js +178 -175
- package/lib/proxy.js +277 -277
- package/lib/reporter.js +1102 -1102
- package/lib/request-utils.js +59 -59
- package/lib/resources.js +76 -76
- package/lib/snapshot.js +41 -41
- package/lib/tmp-cleanup.js +108 -108
- package/lib/tracing.js +137 -137
- package/openclaw.plugin.json +268 -268
- package/package.json +148 -148
- package/plugin.ts +758 -758
- package/plugins/persistence/AGENTS.md +37 -37
- package/plugins/persistence/README.md +48 -48
- package/plugins/persistence/index.js +124 -124
- package/plugins/vnc/AGENTS.md +42 -42
- package/plugins/vnc/README.md +165 -165
- package/plugins/vnc/apt.txt +7 -7
- package/plugins/vnc/index.js +142 -142
- package/plugins/vnc/spawn.js +8 -8
- package/plugins/vnc/vnc-launcher.js +64 -64
- package/plugins/vnc/vnc-watcher.sh +82 -82
- package/plugins/youtube/AGENTS.md +25 -25
- package/plugins/youtube/apt.txt +1 -1
- package/plugins/youtube/index.js +206 -206
- package/plugins/youtube/post-install.sh +5 -5
- package/plugins/youtube/youtube.js +301 -301
- package/run.sh +37 -37
- package/scripts/exec.js +8 -8
- package/scripts/generate-openapi.js +24 -24
- package/scripts/install-plugin-deps.sh +63 -63
- package/scripts/plugin.js +342 -342
- package/scripts/sync-version.js +25 -25
- package/server.js +6062 -6059
- package/tsconfig.json +12 -12
package/lib/tracing.js
CHANGED
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import fsp from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import crypto from 'crypto';
|
|
5
|
-
|
|
6
|
-
function hashUserId(userId) {
|
|
7
|
-
return crypto.createHash('sha256').update(String(userId)).digest('hex').slice(0, 16);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function userTracesDir(baseDir, userId) {
|
|
11
|
-
return path.join(baseDir, hashUserId(userId));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function ensureTracesDir(baseDir, userId) {
|
|
15
|
-
const dir = userTracesDir(baseDir, userId);
|
|
16
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
17
|
-
return dir;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function makeTraceFilename() {
|
|
21
|
-
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
22
|
-
const suffix = crypto.randomBytes(3).toString('hex');
|
|
23
|
-
return `trace-${ts}-${suffix}.zip`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function tracePathFor(baseDir, userId, filename) {
|
|
27
|
-
return path.join(ensureTracesDir(baseDir, userId), filename);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function resolveTracePath(baseDir, userId, filename) {
|
|
31
|
-
if (!filename || filename.includes('/') || filename.includes('\\') || filename.includes('..') || filename.startsWith('.')) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
const userDir = userTracesDir(baseDir, userId);
|
|
35
|
-
const full = path.join(userDir, filename);
|
|
36
|
-
const resolved = path.resolve(full);
|
|
37
|
-
if (!resolved.startsWith(path.resolve(userDir) + path.sep)) return null;
|
|
38
|
-
return resolved;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export async function listUserTraces(baseDir, userId) {
|
|
42
|
-
const dir = userTracesDir(baseDir, userId);
|
|
43
|
-
let names;
|
|
44
|
-
try {
|
|
45
|
-
names = await fsp.readdir(dir);
|
|
46
|
-
} catch {
|
|
47
|
-
return [];
|
|
48
|
-
}
|
|
49
|
-
const out = [];
|
|
50
|
-
for (const name of names) {
|
|
51
|
-
if (!name.endsWith('.zip')) continue;
|
|
52
|
-
const full = path.join(dir, name);
|
|
53
|
-
try {
|
|
54
|
-
const st = await fsp.stat(full);
|
|
55
|
-
if (!st.isFile()) continue;
|
|
56
|
-
out.push({
|
|
57
|
-
filename: name,
|
|
58
|
-
sizeBytes: st.size,
|
|
59
|
-
createdAt: st.birthtimeMs || st.ctimeMs,
|
|
60
|
-
modifiedAt: st.mtimeMs,
|
|
61
|
-
});
|
|
62
|
-
} catch {
|
|
63
|
-
// vanished mid-scan
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
out.sort((a, b) => b.modifiedAt - a.modifiedAt);
|
|
67
|
-
return out;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export async function statTrace(fullPath) {
|
|
71
|
-
try {
|
|
72
|
-
const st = await fsp.stat(fullPath);
|
|
73
|
-
if (!st.isFile()) return null;
|
|
74
|
-
return st;
|
|
75
|
-
} catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export async function deleteTrace(fullPath) {
|
|
81
|
-
await fsp.unlink(fullPath);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function sweepOldTraces({ baseDir, ttlMs, maxBytesPerFile, now = Date.now() } = {}) {
|
|
85
|
-
const result = { scanned: 0, removedTtl: 0, removedOversized: 0, bytes: 0 };
|
|
86
|
-
if (!baseDir) return result;
|
|
87
|
-
|
|
88
|
-
let userDirs;
|
|
89
|
-
try {
|
|
90
|
-
userDirs = fs.readdirSync(baseDir);
|
|
91
|
-
} catch {
|
|
92
|
-
return result;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
for (const userDir of userDirs) {
|
|
96
|
-
const dir = path.join(baseDir, userDir);
|
|
97
|
-
let st;
|
|
98
|
-
try {
|
|
99
|
-
st = fs.statSync(dir);
|
|
100
|
-
} catch {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
if (!st.isDirectory()) continue;
|
|
104
|
-
|
|
105
|
-
let files;
|
|
106
|
-
try {
|
|
107
|
-
files = fs.readdirSync(dir);
|
|
108
|
-
} catch {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
for (const name of files) {
|
|
113
|
-
if (!name.endsWith('.zip')) continue;
|
|
114
|
-
result.scanned++;
|
|
115
|
-
const full = path.join(dir, name);
|
|
116
|
-
try {
|
|
117
|
-
const fst = fs.statSync(full);
|
|
118
|
-
if (!fst.isFile()) continue;
|
|
119
|
-
const tooOld = ttlMs && (now - fst.mtimeMs) > ttlMs;
|
|
120
|
-
const tooBig = maxBytesPerFile && fst.size > maxBytesPerFile;
|
|
121
|
-
if (tooOld) {
|
|
122
|
-
fs.unlinkSync(full);
|
|
123
|
-
result.removedTtl++;
|
|
124
|
-
result.bytes += fst.size;
|
|
125
|
-
} else if (tooBig) {
|
|
126
|
-
fs.unlinkSync(full);
|
|
127
|
-
result.removedOversized++;
|
|
128
|
-
result.bytes += fst.size;
|
|
129
|
-
}
|
|
130
|
-
} catch {
|
|
131
|
-
// vanished or permission denied
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return result;
|
|
137
|
-
}
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import fsp from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import crypto from 'crypto';
|
|
5
|
+
|
|
6
|
+
function hashUserId(userId) {
|
|
7
|
+
return crypto.createHash('sha256').update(String(userId)).digest('hex').slice(0, 16);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function userTracesDir(baseDir, userId) {
|
|
11
|
+
return path.join(baseDir, hashUserId(userId));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ensureTracesDir(baseDir, userId) {
|
|
15
|
+
const dir = userTracesDir(baseDir, userId);
|
|
16
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
17
|
+
return dir;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function makeTraceFilename() {
|
|
21
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
22
|
+
const suffix = crypto.randomBytes(3).toString('hex');
|
|
23
|
+
return `trace-${ts}-${suffix}.zip`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function tracePathFor(baseDir, userId, filename) {
|
|
27
|
+
return path.join(ensureTracesDir(baseDir, userId), filename);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveTracePath(baseDir, userId, filename) {
|
|
31
|
+
if (!filename || filename.includes('/') || filename.includes('\\') || filename.includes('..') || filename.startsWith('.')) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const userDir = userTracesDir(baseDir, userId);
|
|
35
|
+
const full = path.join(userDir, filename);
|
|
36
|
+
const resolved = path.resolve(full);
|
|
37
|
+
if (!resolved.startsWith(path.resolve(userDir) + path.sep)) return null;
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function listUserTraces(baseDir, userId) {
|
|
42
|
+
const dir = userTracesDir(baseDir, userId);
|
|
43
|
+
let names;
|
|
44
|
+
try {
|
|
45
|
+
names = await fsp.readdir(dir);
|
|
46
|
+
} catch {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const out = [];
|
|
50
|
+
for (const name of names) {
|
|
51
|
+
if (!name.endsWith('.zip')) continue;
|
|
52
|
+
const full = path.join(dir, name);
|
|
53
|
+
try {
|
|
54
|
+
const st = await fsp.stat(full);
|
|
55
|
+
if (!st.isFile()) continue;
|
|
56
|
+
out.push({
|
|
57
|
+
filename: name,
|
|
58
|
+
sizeBytes: st.size,
|
|
59
|
+
createdAt: st.birthtimeMs || st.ctimeMs,
|
|
60
|
+
modifiedAt: st.mtimeMs,
|
|
61
|
+
});
|
|
62
|
+
} catch {
|
|
63
|
+
// vanished mid-scan
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
out.sort((a, b) => b.modifiedAt - a.modifiedAt);
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function statTrace(fullPath) {
|
|
71
|
+
try {
|
|
72
|
+
const st = await fsp.stat(fullPath);
|
|
73
|
+
if (!st.isFile()) return null;
|
|
74
|
+
return st;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function deleteTrace(fullPath) {
|
|
81
|
+
await fsp.unlink(fullPath);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function sweepOldTraces({ baseDir, ttlMs, maxBytesPerFile, now = Date.now() } = {}) {
|
|
85
|
+
const result = { scanned: 0, removedTtl: 0, removedOversized: 0, bytes: 0 };
|
|
86
|
+
if (!baseDir) return result;
|
|
87
|
+
|
|
88
|
+
let userDirs;
|
|
89
|
+
try {
|
|
90
|
+
userDirs = fs.readdirSync(baseDir);
|
|
91
|
+
} catch {
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const userDir of userDirs) {
|
|
96
|
+
const dir = path.join(baseDir, userDir);
|
|
97
|
+
let st;
|
|
98
|
+
try {
|
|
99
|
+
st = fs.statSync(dir);
|
|
100
|
+
} catch {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (!st.isDirectory()) continue;
|
|
104
|
+
|
|
105
|
+
let files;
|
|
106
|
+
try {
|
|
107
|
+
files = fs.readdirSync(dir);
|
|
108
|
+
} catch {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (const name of files) {
|
|
113
|
+
if (!name.endsWith('.zip')) continue;
|
|
114
|
+
result.scanned++;
|
|
115
|
+
const full = path.join(dir, name);
|
|
116
|
+
try {
|
|
117
|
+
const fst = fs.statSync(full);
|
|
118
|
+
if (!fst.isFile()) continue;
|
|
119
|
+
const tooOld = ttlMs && (now - fst.mtimeMs) > ttlMs;
|
|
120
|
+
const tooBig = maxBytesPerFile && fst.size > maxBytesPerFile;
|
|
121
|
+
if (tooOld) {
|
|
122
|
+
fs.unlinkSync(full);
|
|
123
|
+
result.removedTtl++;
|
|
124
|
+
result.bytes += fst.size;
|
|
125
|
+
} else if (tooBig) {
|
|
126
|
+
fs.unlinkSync(full);
|
|
127
|
+
result.removedOversized++;
|
|
128
|
+
result.bytes += fst.size;
|
|
129
|
+
}
|
|
130
|
+
} catch {
|
|
131
|
+
// vanished or permission denied
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result;
|
|
137
|
+
}
|