@secure-exec/browser 0.2.0-rc.2 → 0.3.0-rc.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/README.md +4 -5
- package/dist/driver.d.ts +10 -4
- package/dist/driver.js +18 -3
- package/dist/index.d.ts +6 -5
- package/dist/index.js +2 -2
- package/dist/os-filesystem.d.ts +4 -4
- package/dist/os-filesystem.js +28 -11
- package/dist/runtime-driver.d.ts +11 -3
- package/dist/runtime-driver.js +271 -22
- package/dist/runtime.d.ts +222 -0
- package/dist/runtime.js +377 -0
- package/dist/sync-bridge.d.ts +46 -0
- package/dist/sync-bridge.js +49 -0
- package/dist/worker-adapter.js +1 -0
- package/dist/worker-protocol.d.ts +33 -10
- package/dist/worker.js +897 -116
- package/package.json +79 -66
- package/LICENSE +0 -191
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
# Secure Exec
|
|
1
|
+
# Secure Exec Browser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Browser driver primitives for secure-exec.
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
- [GitHub](https://github.com/rivet-dev/secure-exec)
|
|
5
|
+
- Package: `@secure-exec/browser`
|
|
6
|
+
- Exports: `createBrowserDriver`, `createBrowserRuntimeDriverFactory`, `createOpfsFileSystem`, `BrowserWorkerAdapter`
|
package/dist/driver.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type { NetworkAdapter, SystemDriver } from "@secure-exec/core";
|
|
1
|
+
import type { NetworkAdapter, Permissions, SystemDriver, VirtualFileSystem } from "./runtime.js";
|
|
2
|
+
import { createCommandExecutorStub, createFsStub, createNetworkStub } from "./runtime.js";
|
|
4
3
|
export interface BrowserRuntimeSystemOptions {
|
|
5
4
|
filesystem: "opfs" | "memory";
|
|
6
5
|
networkEnabled: boolean;
|
|
@@ -31,6 +30,9 @@ export declare class OpfsFileSystem implements VirtualFileSystem {
|
|
|
31
30
|
stat(path: string): Promise<{
|
|
32
31
|
mode: number;
|
|
33
32
|
size: number;
|
|
33
|
+
blocks: number;
|
|
34
|
+
dev: number;
|
|
35
|
+
rdev: number;
|
|
34
36
|
isDirectory: boolean;
|
|
35
37
|
isSymbolicLink: boolean;
|
|
36
38
|
atimeMs: number;
|
|
@@ -50,6 +52,9 @@ export declare class OpfsFileSystem implements VirtualFileSystem {
|
|
|
50
52
|
lstat(path: string): Promise<{
|
|
51
53
|
mode: number;
|
|
52
54
|
size: number;
|
|
55
|
+
blocks: number;
|
|
56
|
+
dev: number;
|
|
57
|
+
rdev: number;
|
|
53
58
|
isDirectory: boolean;
|
|
54
59
|
isSymbolicLink: boolean;
|
|
55
60
|
atimeMs: number;
|
|
@@ -68,6 +73,7 @@ export declare class OpfsFileSystem implements VirtualFileSystem {
|
|
|
68
73
|
truncate(path: string, length: number): Promise<void>;
|
|
69
74
|
realpath(path: string): Promise<string>;
|
|
70
75
|
pread(path: string, offset: number, length: number): Promise<Uint8Array>;
|
|
76
|
+
pwrite(path: string, offset: number, data: Uint8Array): Promise<void>;
|
|
71
77
|
}
|
|
72
78
|
export interface BrowserDriverOptions {
|
|
73
79
|
filesystem?: "opfs" | "memory";
|
|
@@ -82,4 +88,4 @@ export declare function createBrowserNetworkAdapter(): NetworkAdapter;
|
|
|
82
88
|
export declare function getBrowserSystemDriverOptions(systemDriver: SystemDriver): BrowserRuntimeSystemOptions;
|
|
83
89
|
/** Assemble a browser-side SystemDriver with permission-wrapped adapters. */
|
|
84
90
|
export declare function createBrowserDriver(options?: BrowserDriverOptions): Promise<SystemDriver>;
|
|
85
|
-
export { createCommandExecutorStub, createFsStub, createNetworkStub
|
|
91
|
+
export { createCommandExecutorStub, createFsStub, createNetworkStub };
|
package/dist/driver.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createCommandExecutorStub, createFsStub, createNetworkStub, wrapFileSystem, wrapNetworkAdapter,
|
|
1
|
+
import { createCommandExecutorStub, createEnosysError, createFsStub, createInMemoryFileSystem, createNetworkStub, wrapFileSystem, wrapNetworkAdapter, } from "./runtime.js";
|
|
2
2
|
const S_IFREG = 0o100000;
|
|
3
3
|
const S_IFDIR = 0o040000;
|
|
4
4
|
const BROWSER_SYSTEM_DRIVER_OPTIONS = Symbol.for("secure-exec.browserSystemDriverOptions");
|
|
@@ -133,6 +133,9 @@ export class OpfsFileSystem {
|
|
|
133
133
|
return {
|
|
134
134
|
mode: S_IFREG | 0o644,
|
|
135
135
|
size: file.size,
|
|
136
|
+
blocks: file.size === 0 ? 0 : Math.ceil(file.size / 512),
|
|
137
|
+
dev: 1,
|
|
138
|
+
rdev: 0,
|
|
136
139
|
isDirectory: false,
|
|
137
140
|
isSymbolicLink: false,
|
|
138
141
|
atimeMs: file.lastModified,
|
|
@@ -153,6 +156,9 @@ export class OpfsFileSystem {
|
|
|
153
156
|
return {
|
|
154
157
|
mode: S_IFDIR | 0o755,
|
|
155
158
|
size: 4096,
|
|
159
|
+
blocks: 8,
|
|
160
|
+
dev: 1,
|
|
161
|
+
rdev: 0,
|
|
156
162
|
isDirectory: true,
|
|
157
163
|
isSymbolicLink: false,
|
|
158
164
|
atimeMs: now,
|
|
@@ -227,10 +233,19 @@ export class OpfsFileSystem {
|
|
|
227
233
|
const data = await this.readFile(path);
|
|
228
234
|
return data.slice(offset, offset + length);
|
|
229
235
|
}
|
|
236
|
+
async pwrite(path, offset, data) {
|
|
237
|
+
const content = await this.readFile(path);
|
|
238
|
+
const endPos = offset + data.length;
|
|
239
|
+
const newContent = new Uint8Array(Math.max(content.length, endPos));
|
|
240
|
+
newContent.set(content);
|
|
241
|
+
newContent.set(data, offset);
|
|
242
|
+
await this.writeFile(path, newContent);
|
|
243
|
+
}
|
|
230
244
|
}
|
|
231
245
|
/** Create an OPFS-backed filesystem, falling back to in-memory if OPFS is unavailable. */
|
|
232
246
|
export async function createOpfsFileSystem() {
|
|
233
|
-
if (!("storage" in navigator) ||
|
|
247
|
+
if (!("storage" in navigator) ||
|
|
248
|
+
typeof navigator.storage.getDirectory !== "function") {
|
|
234
249
|
return createInMemoryFileSystem();
|
|
235
250
|
}
|
|
236
251
|
return new OpfsFileSystem();
|
|
@@ -332,4 +347,4 @@ export async function createBrowserDriver(options = {}) {
|
|
|
332
347
|
};
|
|
333
348
|
return systemDriver;
|
|
334
349
|
}
|
|
335
|
-
export { createCommandExecutorStub, createFsStub, createNetworkStub
|
|
350
|
+
export { createCommandExecutorStub, createFsStub, createNetworkStub };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
export { createBrowserDriver, createBrowserNetworkAdapter, createOpfsFileSystem, } from "./driver.js";
|
|
2
1
|
export type { BrowserDriverOptions, BrowserRuntimeSystemOptions, } from "./driver.js";
|
|
3
|
-
export {
|
|
4
|
-
export type { BrowserRuntimeDriverFactoryOptions, } from "./runtime-driver.js";
|
|
5
|
-
export { createInMemoryFileSystem } from "@secure-exec/core";
|
|
2
|
+
export { createBrowserDriver, createBrowserNetworkAdapter, createOpfsFileSystem, } from "./driver.js";
|
|
6
3
|
export { InMemoryFileSystem } from "./os-filesystem.js";
|
|
7
|
-
export {
|
|
4
|
+
export type { ExecOptions, ExecResult, NodeRuntimeDriver, StdioChannel, StdioEvent, TimingMitigation, } from "./runtime.js";
|
|
5
|
+
export { allowAll, allowAllChildProcess, allowAllEnv, allowAllFs, allowAllNetwork, createInMemoryFileSystem, } from "./runtime.js";
|
|
6
|
+
export type { BrowserRuntimeDriverFactoryOptions } from "./runtime-driver.js";
|
|
7
|
+
export { createBrowserRuntimeDriverFactory } from "./runtime-driver.js";
|
|
8
8
|
export type { WorkerHandle } from "./worker-adapter.js";
|
|
9
|
+
export { BrowserWorkerAdapter } from "./worker-adapter.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createBrowserDriver, createBrowserNetworkAdapter, createOpfsFileSystem, } from "./driver.js";
|
|
2
|
-
export { createBrowserRuntimeDriverFactory, } from "./runtime-driver.js";
|
|
3
|
-
export { createInMemoryFileSystem } from "@secure-exec/core";
|
|
4
2
|
export { InMemoryFileSystem } from "./os-filesystem.js";
|
|
3
|
+
export { allowAll, allowAllChildProcess, allowAllEnv, allowAllFs, allowAllNetwork, createInMemoryFileSystem, } from "./runtime.js";
|
|
4
|
+
export { createBrowserRuntimeDriverFactory } from "./runtime-driver.js";
|
|
5
5
|
export { BrowserWorkerAdapter } from "./worker-adapter.js";
|
package/dist/os-filesystem.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* In-memory filesystem for browser environments.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* needed by the kernel VFS interface.
|
|
4
|
+
* In-memory filesystem with POSIX extensions (symlinks, hard links, chmod,
|
|
5
|
+
* chown, utimes, truncate) needed by the kernel VFS interface.
|
|
7
6
|
*/
|
|
8
|
-
import type { VirtualDirEntry, VirtualFileSystem, VirtualStat } from "
|
|
7
|
+
import type { VirtualDirEntry, VirtualFileSystem, VirtualStat } from "./runtime.js";
|
|
9
8
|
export declare class InMemoryFileSystem implements VirtualFileSystem {
|
|
10
9
|
private entries;
|
|
11
10
|
constructor();
|
|
@@ -33,6 +32,7 @@ export declare class InMemoryFileSystem implements VirtualFileSystem {
|
|
|
33
32
|
utimes(path: string, atime: number, mtime: number): Promise<void>;
|
|
34
33
|
truncate(path: string, length: number): Promise<void>;
|
|
35
34
|
pread(path: string, offset: number, length: number): Promise<Uint8Array>;
|
|
35
|
+
pwrite(path: string, offset: number, data: Uint8Array): Promise<void>;
|
|
36
36
|
/**
|
|
37
37
|
* Resolve symlinks to get the final path. Returns the normalized path
|
|
38
38
|
* after following all symlinks.
|
package/dist/os-filesystem.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* In-memory filesystem for browser environments.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* needed by the kernel VFS interface.
|
|
4
|
+
* In-memory filesystem with POSIX extensions (symlinks, hard links, chmod,
|
|
5
|
+
* chown, utimes, truncate) needed by the kernel VFS interface.
|
|
7
6
|
*/
|
|
8
7
|
const S_IFREG = 0o100000;
|
|
9
8
|
const S_IFDIR = 0o040000;
|
|
@@ -30,13 +29,13 @@ function normalizePath(path) {
|
|
|
30
29
|
resolved.push(part);
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
|
-
return
|
|
32
|
+
return `/${resolved.join("/")}` || "/";
|
|
34
33
|
}
|
|
35
34
|
function dirname(path) {
|
|
36
35
|
const parts = normalizePath(path).split("/").filter(Boolean);
|
|
37
36
|
if (parts.length <= 1)
|
|
38
37
|
return "/";
|
|
39
|
-
return
|
|
38
|
+
return `/${parts.slice(0, -1).join("/")}`;
|
|
40
39
|
}
|
|
41
40
|
let nextIno = 1;
|
|
42
41
|
export class InMemoryFileSystem {
|
|
@@ -67,7 +66,7 @@ export class InMemoryFileSystem {
|
|
|
67
66
|
if (!dir || dir.type !== "dir") {
|
|
68
67
|
throw this.enoent("scandir", path);
|
|
69
68
|
}
|
|
70
|
-
const prefix = resolved === "/" ? "/" : resolved
|
|
69
|
+
const prefix = resolved === "/" ? "/" : `${resolved}/`;
|
|
71
70
|
const names = new Map();
|
|
72
71
|
for (const [entryPath, entry] of this.entries) {
|
|
73
72
|
if (entryPath.startsWith(prefix)) {
|
|
@@ -127,7 +126,7 @@ export class InMemoryFileSystem {
|
|
|
127
126
|
const parts = normalized.split("/").filter(Boolean);
|
|
128
127
|
let current = "";
|
|
129
128
|
for (const part of parts) {
|
|
130
|
-
current +=
|
|
129
|
+
current += `/${part}`;
|
|
131
130
|
if (!this.entries.has(current)) {
|
|
132
131
|
this.entries.set(current, this.newDir());
|
|
133
132
|
}
|
|
@@ -170,7 +169,7 @@ export class InMemoryFileSystem {
|
|
|
170
169
|
throw this.enoent("rmdir", path);
|
|
171
170
|
}
|
|
172
171
|
// Check if empty
|
|
173
|
-
const prefix = resolved
|
|
172
|
+
const prefix = `${resolved}/`;
|
|
174
173
|
for (const key of this.entries.keys()) {
|
|
175
174
|
if (key.startsWith(prefix)) {
|
|
176
175
|
throw new Error(`ENOTEMPTY: directory not empty, rmdir '${path}'`);
|
|
@@ -197,7 +196,7 @@ export class InMemoryFileSystem {
|
|
|
197
196
|
return;
|
|
198
197
|
}
|
|
199
198
|
// Move directory and all children
|
|
200
|
-
const prefix = oldResolved
|
|
199
|
+
const prefix = `${oldResolved}/`;
|
|
201
200
|
const toMove = [];
|
|
202
201
|
for (const [key, val] of this.entries) {
|
|
203
202
|
if (key === oldResolved || key.startsWith(prefix)) {
|
|
@@ -317,6 +316,20 @@ export class InMemoryFileSystem {
|
|
|
317
316
|
return new Uint8Array(0);
|
|
318
317
|
return entry.data.slice(offset, Math.min(offset + length, entry.data.length));
|
|
319
318
|
}
|
|
319
|
+
async pwrite(path, offset, data) {
|
|
320
|
+
const entry = this.resolveEntry(path);
|
|
321
|
+
if (!entry || entry.type !== "file") {
|
|
322
|
+
throw this.enoent("open", path);
|
|
323
|
+
}
|
|
324
|
+
const endPos = offset + data.length;
|
|
325
|
+
const newContent = new Uint8Array(Math.max(entry.data.length, endPos));
|
|
326
|
+
newContent.set(entry.data);
|
|
327
|
+
newContent.set(data, offset);
|
|
328
|
+
entry.data = newContent;
|
|
329
|
+
const now = Date.now();
|
|
330
|
+
entry.mtimeMs = now;
|
|
331
|
+
entry.ctimeMs = now;
|
|
332
|
+
}
|
|
320
333
|
// --- Helpers ---
|
|
321
334
|
/**
|
|
322
335
|
* Resolve symlinks to get the final path. Returns the normalized path
|
|
@@ -333,7 +346,7 @@ export class InMemoryFileSystem {
|
|
|
333
346
|
if (entry.type === "symlink") {
|
|
334
347
|
const target = entry.target.startsWith("/")
|
|
335
348
|
? entry.target
|
|
336
|
-
: dirname(normalized)
|
|
349
|
+
: `${dirname(normalized)}/${entry.target}`;
|
|
337
350
|
return this.resolvePath(target, depth + 1);
|
|
338
351
|
}
|
|
339
352
|
return normalized;
|
|
@@ -359,9 +372,13 @@ export class InMemoryFileSystem {
|
|
|
359
372
|
};
|
|
360
373
|
}
|
|
361
374
|
toStat(entry) {
|
|
375
|
+
const size = entry.type === "file" ? entry.data.length : 4096;
|
|
362
376
|
return {
|
|
363
377
|
mode: entry.mode,
|
|
364
|
-
size
|
|
378
|
+
size,
|
|
379
|
+
blocks: size === 0 ? 0 : Math.ceil(size / 512),
|
|
380
|
+
dev: 1,
|
|
381
|
+
rdev: 0,
|
|
365
382
|
isDirectory: entry.type === "dir",
|
|
366
383
|
isSymbolicLink: entry.type === "symlink",
|
|
367
384
|
atimeMs: entry.atimeMs,
|
package/dist/runtime-driver.d.ts
CHANGED
|
@@ -1,25 +1,33 @@
|
|
|
1
|
-
import type { NetworkAdapter, NodeRuntimeDriver, NodeRuntimeDriverFactory, RuntimeDriverOptions } from "
|
|
2
|
-
import type { ExecOptions, ExecResult, RunResult } from "@secure-exec/core";
|
|
1
|
+
import type { ExecOptions, ExecResult, NetworkAdapter, NodeRuntimeDriver, NodeRuntimeDriverFactory, RunResult, RuntimeDriverOptions } from "./runtime.js";
|
|
3
2
|
export interface BrowserRuntimeDriverFactoryOptions {
|
|
4
3
|
workerUrl?: URL | string;
|
|
5
4
|
}
|
|
6
5
|
export declare class BrowserRuntimeDriver implements NodeRuntimeDriver {
|
|
7
|
-
private readonly options;
|
|
8
6
|
private readonly worker;
|
|
9
7
|
private readonly pending;
|
|
8
|
+
private readonly controlToken;
|
|
10
9
|
private readonly defaultOnStdio?;
|
|
10
|
+
private readonly defaultTimingMitigation;
|
|
11
11
|
private readonly networkAdapter;
|
|
12
|
+
private readonly syncBridge;
|
|
13
|
+
private readonly syncFilesystem;
|
|
12
14
|
private readonly ready;
|
|
15
|
+
private readonly encoder;
|
|
13
16
|
private nextId;
|
|
14
17
|
private disposed;
|
|
15
18
|
constructor(options: RuntimeDriverOptions, factoryOptions?: BrowserRuntimeDriverFactoryOptions);
|
|
16
19
|
get network(): Pick<NetworkAdapter, "fetch" | "dnsLookup" | "httpRequest">;
|
|
17
20
|
private handleWorkerError;
|
|
18
21
|
private handleWorkerMessage;
|
|
22
|
+
private handleSyncRequest;
|
|
19
23
|
private rejectAllPending;
|
|
24
|
+
private clearWorkerHandlers;
|
|
25
|
+
private resetSyncBridgeState;
|
|
26
|
+
private cleanup;
|
|
20
27
|
private callWorker;
|
|
21
28
|
run<T = unknown>(code: string, filePath?: string): Promise<RunResult<T>>;
|
|
22
29
|
exec(code: string, options?: ExecOptions): Promise<ExecResult>;
|
|
30
|
+
dispatchExtensionRequest(namespace: string, payload: Uint8Array): Promise<Uint8Array>;
|
|
23
31
|
dispose(): void;
|
|
24
32
|
terminate(): Promise<void>;
|
|
25
33
|
}
|