-
Notifications
You must be signed in to change notification settings - Fork 159
Expand file tree
/
Copy pathsandbox.js
More file actions
156 lines (129 loc) · 3.91 KB
/
sandbox.js
File metadata and controls
156 lines (129 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
'use strict';
const chalk = require('chalk');
const vm = require('vm');
const sourceMapSupport = require('source-map-support');
const httpRegex = /^https?:\/\//;
const protocolRelativeRegex = /^\/\//;
module.exports = class Sandbox {
constructor(globals) {
this.globals = globals;
let sandbox = this.buildSandbox();
this.context = vm.createContext(sandbox);
}
buildSandbox() {
let console = this.buildWrappedConsole();
let fetch = this.buildFetch();
let URL = require('url');
let globals = this.globals;
let sandbox = Object.assign(
{
sourceMapSupport,
console,
setTimeout,
clearTimeout,
URL,
// Convince jQuery not to assume it's in a browser
module: { exports: {} },
},
fetch,
globals
);
// Set the global as `window`.
sandbox.window = sandbox;
sandbox.window.self = sandbox;
return sandbox;
}
buildWrappedConsole() {
let wrappedConsole = Object.create(console);
wrappedConsole.error = function(...args) {
console.error.apply(
console,
args.map(function(a) {
return typeof a === 'string' ? chalk.red(a) : a;
})
);
};
return wrappedConsole;
}
buildFetch() {
let globals;
if (globalThis.fetch) {
globals = {
fetch: globalThis.fetch,
Request: globalThis.Request,
Response: globalThis.Response,
Headers: globalThis.Headers,
AbortController: globalThis.AbortController,
};
} else {
let nodeFetch = require('node-fetch');
let {
AbortController,
abortableFetch,
} = require('abortcontroller-polyfill/dist/cjs-ponyfill');
let { fetch, Request } = abortableFetch({
fetch: nodeFetch,
Request: nodeFetch.Request,
});
globals = {
fetch,
Request,
Response: nodeFetch.Response,
Headers: nodeFetch.Headers,
AbortController,
};
}
let originalFetch = globals.fetch;
globals.fetch = function __fastbootFetch(input, init) {
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
return originalFetch(input, init);
};
globals.fetch.__fastbootBuildAbsoluteURL = function __fastbootBuildAbsoluteURL(input) {
if (input && input.href) {
// WHATWG URL or Node.js Url Object
input = input.href;
}
if (typeof input !== 'string') {
return input;
}
if (protocolRelativeRegex.test(input)) {
let request = globals.fetch.__fastbootRequest;
let [protocol] = globals.fetch.__fastbootParseRequest(input, request);
input = `${protocol}//${input}`;
} else if (!httpRegex.test(input)) {
let request = globals.fetch.__fastbootRequest;
let [protocol, host] = globals.fetch.__fastbootParseRequest(input, request);
input = `${protocol}//${host}${input}`;
}
return input;
};
globals.fetch.__fastbootParseRequest = function __fastbootParseRequest(url, request) {
if (!request) {
throw new Error(
`Using fetch with relative URL ${url}, but application instance has not been initialized yet.`
);
}
// Old Prember version is not sending protocol
const protocol = request.protocol === 'undefined:' ? 'http:' : request.protocol;
return [protocol, request.host];
};
let OriginalRequest = globals.Request;
globals.Request = class __FastBootRequest extends OriginalRequest {
constructor(input, init) {
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
super(input, init);
}
};
return globals;
}
runScript(script) {
script.runInContext(this.context);
}
eval(source, filePath) {
var fileScript = new vm.Script(source, { filename: filePath });
fileScript.runInContext(this.context);
}
run(cb) {
return cb.call(this.context, this.context);
}
};