warden.rn 1.0.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.
- package/README.MD +13 -0
- package/dist/build/deps.d.ts +4 -0
- package/dist/build/deps.js +50 -0
- package/dist/build/globals.d.ts +6 -0
- package/dist/build/globals.js +419 -0
- package/dist/build/harden.d.ts +7 -0
- package/dist/build/harden.js +109 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +150 -0
- package/dist/util/bimap.d.ts +19 -0
- package/dist/util/bimap.js +96 -0
- package/dist/util/config.d.ts +18 -0
- package/dist/util/config.js +59 -0
- package/dist/util/util.d.ts +16 -0
- package/dist/util/util.js +89 -0
- package/package.json +30 -0
package/README.MD
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# RN应用三方代码权限管理工具
|
|
2
|
+
## 引入形式
|
|
3
|
+
作为Metro构建工具的自定义Serializer引入,在metro.config.js中引入
|
|
4
|
+
如果有多个serializer,需要将WardenSerializer置于最外层
|
|
5
|
+
```js
|
|
6
|
+
serializer: {
|
|
7
|
+
customSerializer: createWardenSerializer(createSentryMetroSerializer(), {
|
|
8
|
+
// ... 配置项
|
|
9
|
+
}),
|
|
10
|
+
},
|
|
11
|
+
```
|
|
12
|
+
## 配置
|
|
13
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.protectRequire = protectRequire;
|
|
4
|
+
const parser_1 = require("@babel/parser");
|
|
5
|
+
const t = require("@babel/types");
|
|
6
|
+
function protectRequire(fn, deps) {
|
|
7
|
+
const require = fn.node.params[1];
|
|
8
|
+
if (!t.isIdentifier(require)) {
|
|
9
|
+
throw new Error(`require must be an identifier`);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const importDefault = fn.node.params[2];
|
|
13
|
+
if (!t.isIdentifier(importDefault)) {
|
|
14
|
+
throw new Error(`importDefault must be an identifier`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const importAll = fn.node.params[3];
|
|
18
|
+
if (!t.isIdentifier(importAll)) {
|
|
19
|
+
throw new Error(`importAll must be an identifier`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const template = `
|
|
23
|
+
() => {
|
|
24
|
+
const __r0 = ${JSON.stringify(deps)};
|
|
25
|
+
const __r1 = ${require.name};
|
|
26
|
+
const __r2 = ${importDefault.name};
|
|
27
|
+
const __r3 = ${importAll.name};
|
|
28
|
+
${require.name} = function(i) {
|
|
29
|
+
if (__r0.includes(i)) {
|
|
30
|
+
return __r1(i);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
${importDefault.name} = function(i) {
|
|
34
|
+
if (__r0.includes(i)) {
|
|
35
|
+
return __r2(i);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
${importAll.name} = function(i) {
|
|
39
|
+
if (__r0.includes(i)) {
|
|
40
|
+
return __r3(i);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
${require.name}.importDefault = __r2;
|
|
44
|
+
${require.name}.importAll = __r3;
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
const ppFn = (0, parser_1.parseExpression)(template);
|
|
48
|
+
fn.node.body.body.unshift(t.expressionStatement(t.callExpression(ppFn, [])));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=deps.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { NodePath } from "@babel/traverse";
|
|
3
|
+
export declare function refactorRuntime(file: t.File, id2path?: Record<number, string>, dev?: boolean): void;
|
|
4
|
+
export declare function analyzeGlobals(ast: NodePath<t.CallExpression>, normalize?: boolean): Record<string, "r" | "rw">;
|
|
5
|
+
export declare function hardenGlobals(ast: NodePath<t.CallExpression>, globals: Record<string, "r" | "rw">, moduleId: number, dev?: boolean): void;
|
|
6
|
+
//# sourceMappingURL=globals.d.ts.map
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.refactorRuntime = refactorRuntime;
|
|
4
|
+
exports.analyzeGlobals = analyzeGlobals;
|
|
5
|
+
exports.hardenGlobals = hardenGlobals;
|
|
6
|
+
const t = require("@babel/types");
|
|
7
|
+
const parser_1 = require("@babel/parser");
|
|
8
|
+
const ECMAGlobals = [
|
|
9
|
+
"AggregateError",
|
|
10
|
+
"Array",
|
|
11
|
+
"ArrayBuffer",
|
|
12
|
+
"Atomics",
|
|
13
|
+
"BigInt",
|
|
14
|
+
"BigInt64Array",
|
|
15
|
+
"BigUint64Array",
|
|
16
|
+
"Boolean",
|
|
17
|
+
"DataView",
|
|
18
|
+
"Date",
|
|
19
|
+
"Error",
|
|
20
|
+
"EvalError",
|
|
21
|
+
"FinalizationRegistry",
|
|
22
|
+
"Float16Array",
|
|
23
|
+
"Float32Array",
|
|
24
|
+
"Float64Array",
|
|
25
|
+
"Function",
|
|
26
|
+
"Infinity",
|
|
27
|
+
"Int16Array",
|
|
28
|
+
"Int32Array",
|
|
29
|
+
"Int8Array",
|
|
30
|
+
"Intl",
|
|
31
|
+
"Iterator",
|
|
32
|
+
"JSON",
|
|
33
|
+
"Map",
|
|
34
|
+
"Math",
|
|
35
|
+
"NaN",
|
|
36
|
+
"Number",
|
|
37
|
+
"Object",
|
|
38
|
+
"Promise",
|
|
39
|
+
"Proxy",
|
|
40
|
+
"RangeError",
|
|
41
|
+
"ReferenceError",
|
|
42
|
+
"Reflect",
|
|
43
|
+
"RegExp",
|
|
44
|
+
"Set",
|
|
45
|
+
"SharedArrayBuffer",
|
|
46
|
+
"String",
|
|
47
|
+
"Symbol",
|
|
48
|
+
"SyntaxError",
|
|
49
|
+
"TypeError",
|
|
50
|
+
"Uint16Array",
|
|
51
|
+
"Uint32Array",
|
|
52
|
+
"Uint8Array",
|
|
53
|
+
"Uint8ClampedArray",
|
|
54
|
+
"URIError",
|
|
55
|
+
"WeakMap",
|
|
56
|
+
"WeakRef",
|
|
57
|
+
"WeakSet",
|
|
58
|
+
"decodeURI",
|
|
59
|
+
"decodeURIComponent",
|
|
60
|
+
"encodeURI",
|
|
61
|
+
"encodeURIComponent",
|
|
62
|
+
"escape",
|
|
63
|
+
// "eval",
|
|
64
|
+
"globalThis",
|
|
65
|
+
"isFinite",
|
|
66
|
+
"isNaN",
|
|
67
|
+
"parseFloat",
|
|
68
|
+
"parseInt",
|
|
69
|
+
"undefined",
|
|
70
|
+
"unescape",
|
|
71
|
+
];
|
|
72
|
+
class GVPool {
|
|
73
|
+
globals = Object.create(null);
|
|
74
|
+
add(name, perm) {
|
|
75
|
+
// 不管控除eval以外的ECMA全局变量的读权限
|
|
76
|
+
if (ECMAGlobals.includes(name) && perm === "r") {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (name in this.globals) {
|
|
80
|
+
if (perm === "rw") {
|
|
81
|
+
this.globals[name] = "rw";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
this.globals[name] = perm;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function __mkGb(g, fg, moduleId, dev = false) {
|
|
90
|
+
if (dev) {
|
|
91
|
+
//@ts-expect-error
|
|
92
|
+
if (globalThis.__warden_globals == null) {
|
|
93
|
+
//@ts-expect-error
|
|
94
|
+
globalThis.__warden_globals = Object.create(null);
|
|
95
|
+
}
|
|
96
|
+
//@ts-expect-error
|
|
97
|
+
if (globalThis.__warden_globals[moduleId] == null) {
|
|
98
|
+
//@ts-expect-error
|
|
99
|
+
globalThis.__warden_globals[moduleId] = Object.create(null);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const ECMAGlobals = [
|
|
103
|
+
"AggregateError",
|
|
104
|
+
"Array",
|
|
105
|
+
"ArrayBuffer",
|
|
106
|
+
"Atomics",
|
|
107
|
+
"BigInt",
|
|
108
|
+
"BigInt64Array",
|
|
109
|
+
"BigUint64Array",
|
|
110
|
+
"Boolean",
|
|
111
|
+
"DataView",
|
|
112
|
+
"Date",
|
|
113
|
+
"Error",
|
|
114
|
+
"EvalError",
|
|
115
|
+
"FinalizationRegistry",
|
|
116
|
+
"Float16Array",
|
|
117
|
+
"Float32Array",
|
|
118
|
+
"Float64Array",
|
|
119
|
+
"Function",
|
|
120
|
+
"Infinity",
|
|
121
|
+
"Int16Array",
|
|
122
|
+
"Int32Array",
|
|
123
|
+
"Int8Array",
|
|
124
|
+
"Intl",
|
|
125
|
+
"Iterator",
|
|
126
|
+
"JSON",
|
|
127
|
+
"Map",
|
|
128
|
+
"Math",
|
|
129
|
+
"NaN",
|
|
130
|
+
"Number",
|
|
131
|
+
"Object",
|
|
132
|
+
"Promise",
|
|
133
|
+
"Proxy",
|
|
134
|
+
"RangeError",
|
|
135
|
+
"ReferenceError",
|
|
136
|
+
"Reflect",
|
|
137
|
+
"RegExp",
|
|
138
|
+
"Set",
|
|
139
|
+
"SharedArrayBuffer",
|
|
140
|
+
"String",
|
|
141
|
+
"Symbol",
|
|
142
|
+
"SyntaxError",
|
|
143
|
+
"TypeError",
|
|
144
|
+
"Uint16Array",
|
|
145
|
+
"Uint32Array",
|
|
146
|
+
"Uint8Array",
|
|
147
|
+
"Uint8ClampedArray",
|
|
148
|
+
"URIError",
|
|
149
|
+
"WeakMap",
|
|
150
|
+
"WeakRef",
|
|
151
|
+
"WeakSet",
|
|
152
|
+
"decodeURI",
|
|
153
|
+
"decodeURIComponent",
|
|
154
|
+
"encodeURI",
|
|
155
|
+
"encodeURIComponent",
|
|
156
|
+
"escape",
|
|
157
|
+
// "eval",
|
|
158
|
+
"globalThis",
|
|
159
|
+
"isFinite",
|
|
160
|
+
"isNaN",
|
|
161
|
+
"parseFloat",
|
|
162
|
+
"parseInt",
|
|
163
|
+
"undefined",
|
|
164
|
+
"unescape",
|
|
165
|
+
];
|
|
166
|
+
const np = new Proxy(fg != null ? fg : globalThis, {
|
|
167
|
+
get(t, p, r) {
|
|
168
|
+
if (typeof p === "symbol") {
|
|
169
|
+
return Reflect.get(t, p, t);
|
|
170
|
+
}
|
|
171
|
+
if (["globalThis", "self", "window", "global"].includes(p)) {
|
|
172
|
+
return t;
|
|
173
|
+
}
|
|
174
|
+
if (p in g || ECMAGlobals.includes(p)) {
|
|
175
|
+
return Reflect.get(t, p, t);
|
|
176
|
+
}
|
|
177
|
+
if (dev) {
|
|
178
|
+
//@ts-expect-error
|
|
179
|
+
if (!(p in globalThis.__warden_globals[moduleId])) {
|
|
180
|
+
//@ts-expect-error
|
|
181
|
+
globalThis.__warden_globals[moduleId][p] = "r";
|
|
182
|
+
}
|
|
183
|
+
return Reflect.get(t, p, t);
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
},
|
|
187
|
+
has(t, p) {
|
|
188
|
+
if (typeof p === "symbol") {
|
|
189
|
+
return Reflect.has(t, p);
|
|
190
|
+
}
|
|
191
|
+
if (p in g || ECMAGlobals.includes(p)) {
|
|
192
|
+
return Reflect.has(t, p);
|
|
193
|
+
}
|
|
194
|
+
if (dev) {
|
|
195
|
+
//@ts-expect-error
|
|
196
|
+
if (!(p in globalThis.__warden_globals[moduleId])) {
|
|
197
|
+
//@ts-expect-error
|
|
198
|
+
globalThis.__warden_globals[moduleId][p] = "r";
|
|
199
|
+
}
|
|
200
|
+
return Reflect.has(t, p);
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
},
|
|
204
|
+
set(t, p, n, r) {
|
|
205
|
+
if (typeof p === "symbol") {
|
|
206
|
+
return Reflect.set(t, p, n, t);
|
|
207
|
+
}
|
|
208
|
+
if (p in g) {
|
|
209
|
+
return Reflect.set(t, p, n, t);
|
|
210
|
+
}
|
|
211
|
+
if (dev) {
|
|
212
|
+
//@ts-expect-error
|
|
213
|
+
if (!(p in globalThis.__warden_globals)) {
|
|
214
|
+
//@ts-expect-error
|
|
215
|
+
globalThis.__warden_globals[moduleId][p] = "rw";
|
|
216
|
+
}
|
|
217
|
+
return Reflect.set(t, p, n, t);
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
},
|
|
221
|
+
getOwnPropertyDescriptor(t, p) {
|
|
222
|
+
if (typeof p === "symbol") {
|
|
223
|
+
return Reflect.getOwnPropertyDescriptor(t, p);
|
|
224
|
+
}
|
|
225
|
+
if (p in g || ECMAGlobals.includes(p)) {
|
|
226
|
+
return Reflect.getOwnPropertyDescriptor(t, p);
|
|
227
|
+
}
|
|
228
|
+
if (dev) {
|
|
229
|
+
//@ts-expect-error
|
|
230
|
+
if (!(p in globalThis.__warden_globals)) {
|
|
231
|
+
//@ts-expect-error
|
|
232
|
+
globalThis.__warden_globals[moduleId][p] = "r";
|
|
233
|
+
}
|
|
234
|
+
return Reflect.getOwnPropertyDescriptor(t, p);
|
|
235
|
+
}
|
|
236
|
+
return undefined;
|
|
237
|
+
},
|
|
238
|
+
defineProperty(t, p, d) {
|
|
239
|
+
if (typeof p === "symbol") {
|
|
240
|
+
return Reflect.defineProperty(t, p, d);
|
|
241
|
+
}
|
|
242
|
+
if (p in g) {
|
|
243
|
+
return Reflect.defineProperty(t, p, d);
|
|
244
|
+
}
|
|
245
|
+
if (dev) {
|
|
246
|
+
//@ts-expect-error
|
|
247
|
+
if (!(p in globalThis.__warden_globals[moduleId])) {
|
|
248
|
+
//@ts-expect-error
|
|
249
|
+
globalThis.__warden_globals[moduleId][p] = "rw";
|
|
250
|
+
}
|
|
251
|
+
return Reflect.defineProperty(t, p, d);
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
},
|
|
255
|
+
deleteProperty(t, p) {
|
|
256
|
+
if (typeof p === "symbol") {
|
|
257
|
+
return Reflect.deleteProperty(t, p);
|
|
258
|
+
}
|
|
259
|
+
if (p in g) {
|
|
260
|
+
return Reflect.deleteProperty(t, p);
|
|
261
|
+
}
|
|
262
|
+
if (dev) {
|
|
263
|
+
//@ts-expect-error
|
|
264
|
+
if (!(p in globalThis.__warden_globals[moduleId])) {
|
|
265
|
+
//@ts-expect-error
|
|
266
|
+
globalThis.__warden_globals[moduleId][p] = "rw";
|
|
267
|
+
}
|
|
268
|
+
return Reflect.deleteProperty(t, p);
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
return np;
|
|
274
|
+
}
|
|
275
|
+
function refactorRuntime(file, id2path = {}, dev = false) {
|
|
276
|
+
const debugGb = (id2Path) => {
|
|
277
|
+
const result = Object.create(null);
|
|
278
|
+
for (const [id, gb] of Object.entries(globalThis.__warden_globals)) {
|
|
279
|
+
if (Object.keys(gb).length === 0) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const path = id2Path[id];
|
|
283
|
+
result[path] = gb;
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
};
|
|
287
|
+
if (dev) {
|
|
288
|
+
file.program.body.unshift(t.expressionStatement(t.assignmentExpression("=", t.memberExpression(t.identifier("globalThis"), t.identifier("__debugGb")), (0, parser_1.parseExpression)(`(${debugGb.toString()}).bind(null, ${JSON.stringify(id2path)})`))));
|
|
289
|
+
}
|
|
290
|
+
file.program.body.unshift(t.expressionStatement(t.assignmentExpression("=", t.memberExpression(t.identifier("globalThis"), t.identifier("__mkGb")), (0, parser_1.parseExpression)(__mkGb.toString()))));
|
|
291
|
+
}
|
|
292
|
+
function analyzeGlobals(ast, normalize = false) {
|
|
293
|
+
const pool = new GVPool();
|
|
294
|
+
const fn = ast.get("arguments")[0];
|
|
295
|
+
const globalAlias = ["globalThis", "self", "window", "g", "global"];
|
|
296
|
+
fn.traverse({
|
|
297
|
+
MemberExpression(path) {
|
|
298
|
+
let expr = [];
|
|
299
|
+
let node = path.node;
|
|
300
|
+
let flag = true;
|
|
301
|
+
while (t.isMemberExpression(node)) {
|
|
302
|
+
if (t.isIdentifier(node.property) && !node.computed) {
|
|
303
|
+
expr.unshift(node.property.name);
|
|
304
|
+
}
|
|
305
|
+
else if (t.isStringLiteral(node.property)) {
|
|
306
|
+
expr.unshift(node.property.value);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
flag = false;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
if (t.isIdentifier(node.object)) {
|
|
313
|
+
expr.unshift(node.object.name);
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
else if (t.isMemberExpression(node.object)) {
|
|
317
|
+
node = node.object;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
flag = false;
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (!flag) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
let mustBeGlobal = false;
|
|
328
|
+
while (expr.length > 0 && globalAlias.includes(expr[0])) {
|
|
329
|
+
expr = expr.slice(1);
|
|
330
|
+
// 如果是globalThis/self/window开头的, 则一定是全局变量
|
|
331
|
+
mustBeGlobal = true;
|
|
332
|
+
}
|
|
333
|
+
if (expr.length > 0 &&
|
|
334
|
+
(mustBeGlobal ||
|
|
335
|
+
!path.scope.hasBinding(expr[0], { noGlobals: true })) &&
|
|
336
|
+
expr[0] !== "arguments") {
|
|
337
|
+
pool.add(expr[0], t.isAssignmentExpression(path.parent) &&
|
|
338
|
+
path.parent.left === path.node &&
|
|
339
|
+
expr.length === 1
|
|
340
|
+
? "rw"
|
|
341
|
+
: "r");
|
|
342
|
+
}
|
|
343
|
+
path.skip();
|
|
344
|
+
},
|
|
345
|
+
Identifier(path) {
|
|
346
|
+
if (!path.scope.hasBinding(path.node.name, { noGlobals: true })) {
|
|
347
|
+
// 排除一些不算真正变量读取的场景
|
|
348
|
+
if ((t.isMemberExpression(path.parent) ||
|
|
349
|
+
t.isOptionalMemberExpression(path.parent)) &&
|
|
350
|
+
path.parent.property === path.node) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
else if (t.isObjectProperty(path.parent) &&
|
|
354
|
+
path.parent.key === path.node) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
else if ((t.isLabeledStatement(path.parent) ||
|
|
358
|
+
t.isBreakStatement(path.parent) ||
|
|
359
|
+
t.isContinueStatement(path.parent)) &&
|
|
360
|
+
path.parent.label === path.node) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
else if ((t.isFunctionDeclaration(path.parent) ||
|
|
364
|
+
t.isFunctionExpression(path.parent)) &&
|
|
365
|
+
path.parent.id === path.node) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
else if (t.isCatchClause(path.parent) &&
|
|
369
|
+
path.parent.param === path.node) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
else if (t.isFunction(path.parent) &&
|
|
373
|
+
(path.parent.params.includes(path.node) ||
|
|
374
|
+
path.parent.id === path.node ||
|
|
375
|
+
path.parent.kind === path.node.name ||
|
|
376
|
+
path.parent.key === path.node)) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
else if (t.isMetaProperty(path.parent)) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
else if (t.isClassProperty(path.parent) &&
|
|
383
|
+
path.parent.key === path.node) {
|
|
384
|
+
return;
|
|
385
|
+
// globalAlias默认可访问
|
|
386
|
+
}
|
|
387
|
+
else if (globalAlias.includes(path.node.name)) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
else if (path.node.name === "arguments") {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
pool.add(path.node.name, t.isAssignmentExpression(path.parent) &&
|
|
394
|
+
path.parent.left === path.node
|
|
395
|
+
? "rw"
|
|
396
|
+
: "r");
|
|
397
|
+
if (normalize && !ECMAGlobals.includes(path.node.name)) {
|
|
398
|
+
path.replaceWith(t.memberExpression(t.identifier("self"), path.node, false));
|
|
399
|
+
path.skip();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
return pool.globals;
|
|
405
|
+
}
|
|
406
|
+
function hardenGlobals(ast, globals, moduleId, dev = false) {
|
|
407
|
+
const fn = ast.get("arguments")[0];
|
|
408
|
+
const id = fn.node.params[0];
|
|
409
|
+
if (!t.isIdentifier(id)) {
|
|
410
|
+
throw new Error("The first parameter of the function must be an identifier");
|
|
411
|
+
}
|
|
412
|
+
fn.node.body.body.unshift(t.variableDeclaration("var", [
|
|
413
|
+
t.variableDeclarator(t.identifier("global"), (0, parser_1.parseExpression)(`__mkGb(Object.assign(Object.create(null), ${JSON.stringify(globals)}), ${id.name}, ${moduleId}, ${dev})`)),
|
|
414
|
+
t.variableDeclarator(t.identifier("globalThis"), t.identifier("global")),
|
|
415
|
+
t.variableDeclarator(t.identifier("self"), t.identifier("global")),
|
|
416
|
+
t.variableDeclarator(t.identifier("window"), t.identifier("global")),
|
|
417
|
+
]), t.expressionStatement((0, parser_1.parseExpression)(`${id.name} = global`)));
|
|
418
|
+
}
|
|
419
|
+
//# sourceMappingURL=globals.js.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file build/harden.ts
|
|
4
|
+
* 添加原型链保护
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.addPrototypePollutionGuard = addPrototypePollutionGuard;
|
|
8
|
+
const t = require("@babel/types");
|
|
9
|
+
const parser_1 = require("@babel/parser");
|
|
10
|
+
function hardenPrototype() {
|
|
11
|
+
//@ts-expect-error
|
|
12
|
+
const valueArr = [];
|
|
13
|
+
//@ts-expect-error
|
|
14
|
+
globalThis.valueArr = valueArr;
|
|
15
|
+
const lock_Objects = ["Array", "Object"];
|
|
16
|
+
const skipSet = new Set(["size", "length", "name", "stack"]);
|
|
17
|
+
for (const objName of lock_Objects) {
|
|
18
|
+
//@ts-expect-error
|
|
19
|
+
const obj = globalThis[objName];
|
|
20
|
+
if (obj) {
|
|
21
|
+
Object.freeze(obj);
|
|
22
|
+
if (obj.prototype) {
|
|
23
|
+
const prototype = obj.prototype;
|
|
24
|
+
for (const k of Object.getOwnPropertyNames(prototype)) {
|
|
25
|
+
const propKey = k;
|
|
26
|
+
if (skipSet.has(propKey)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const desc = Object.getOwnPropertyDescriptor(prototype, propKey);
|
|
30
|
+
if (desc &&
|
|
31
|
+
desc.value &&
|
|
32
|
+
desc.writable &&
|
|
33
|
+
desc.configurable) {
|
|
34
|
+
const ovalue = desc.value;
|
|
35
|
+
delete desc.value;
|
|
36
|
+
delete desc.writable;
|
|
37
|
+
valueArr.push(ovalue);
|
|
38
|
+
const code = `
|
|
39
|
+
if (this === ${objName}.prototype || this == null) {
|
|
40
|
+
return globalThis.valueArr[${valueArr.length - 1}]
|
|
41
|
+
} else {
|
|
42
|
+
return Object.getPrototypeOf(this).${propKey};
|
|
43
|
+
}`;
|
|
44
|
+
//@ts-expect-error
|
|
45
|
+
desc.get = new Function(code);
|
|
46
|
+
//@ts-expect-error
|
|
47
|
+
desc.set = new Function("v", `
|
|
48
|
+
if (this === ${objName}.prototype) {
|
|
49
|
+
return;
|
|
50
|
+
} else {
|
|
51
|
+
Object.defineProperty(this, "${propKey}", {
|
|
52
|
+
value: v,
|
|
53
|
+
writable: true,
|
|
54
|
+
configurable: true,
|
|
55
|
+
enumerable: true,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
`);
|
|
59
|
+
desc.configurable = false;
|
|
60
|
+
Object.defineProperty(prototype, propKey, desc);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// 禁止动态代码执行
|
|
67
|
+
const blockError = () => {
|
|
68
|
+
throw new Error('Dynamic code execution is not allowed');
|
|
69
|
+
};
|
|
70
|
+
// 拦截 Function 构造函数
|
|
71
|
+
const OriginalFunction = Function;
|
|
72
|
+
const FunctionProxy = new Proxy(OriginalFunction, {
|
|
73
|
+
construct: blockError,
|
|
74
|
+
apply: blockError,
|
|
75
|
+
});
|
|
76
|
+
// 替换全局 Function
|
|
77
|
+
try {
|
|
78
|
+
Object.defineProperty(globalThis, 'Function', {
|
|
79
|
+
value: FunctionProxy,
|
|
80
|
+
writable: false,
|
|
81
|
+
configurable: false,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
// 如果无法替换,尝试直接赋值
|
|
86
|
+
globalThis.Function = FunctionProxy;
|
|
87
|
+
}
|
|
88
|
+
// 拦截 async function constructor
|
|
89
|
+
//@ts-expect-error
|
|
90
|
+
const asyncProto = (async function () { }).__proto__;
|
|
91
|
+
Object.defineProperty(asyncProto, 'constructor', {
|
|
92
|
+
get: blockError,
|
|
93
|
+
configurable: false,
|
|
94
|
+
enumerable: false,
|
|
95
|
+
});
|
|
96
|
+
// 拦截 generator function constructor
|
|
97
|
+
//@ts-expect-error
|
|
98
|
+
const genProto = (function* () { }).__proto__;
|
|
99
|
+
Object.defineProperty(genProto, 'constructor', {
|
|
100
|
+
get: blockError,
|
|
101
|
+
configurable: false,
|
|
102
|
+
enumerable: false,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function addPrototypePollutionGuard(ast) {
|
|
106
|
+
const hardenPrototypeAst = t.expressionStatement(t.callExpression((0, parser_1.parseExpression)(hardenPrototype.toString()), []));
|
|
107
|
+
ast.program.body.unshift(hardenPrototypeAst);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=harden.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MetroSerializer } from "./types/util";
|
|
2
|
+
export type Options = {
|
|
3
|
+
dev: boolean | undefined;
|
|
4
|
+
sourceRoot: string | undefined;
|
|
5
|
+
policyDir: string | undefined;
|
|
6
|
+
rootDir: string | undefined;
|
|
7
|
+
};
|
|
8
|
+
export declare function createWardenSerializer(serilaizer: MetroSerializer | undefined, config: Options): MetroSerializer;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWardenSerializer = createWardenSerializer;
|
|
4
|
+
const util_1 = require("./util/util");
|
|
5
|
+
const bimap_1 = require("./util/bimap");
|
|
6
|
+
const parser_1 = require("@babel/parser");
|
|
7
|
+
const traverse_1 = require("@babel/traverse");
|
|
8
|
+
const t = require("@babel/types");
|
|
9
|
+
const generator_1 = require("@babel/generator");
|
|
10
|
+
const remapping = require("@ampproject/remapping");
|
|
11
|
+
const harden_1 = require("./build/harden");
|
|
12
|
+
const config_1 = require("./util/config");
|
|
13
|
+
const globals_1 = require("./build/globals");
|
|
14
|
+
const node_fs_1 = require("node:fs");
|
|
15
|
+
const path = require("node:path");
|
|
16
|
+
const deps_1 = require("./build/deps");
|
|
17
|
+
function createWardenSerializer(serilaizer = undefined, config) {
|
|
18
|
+
if (config == null) {
|
|
19
|
+
throw new Error(`please specify options`);
|
|
20
|
+
}
|
|
21
|
+
if (config.sourceRoot == null) {
|
|
22
|
+
config.sourceRoot = "./src";
|
|
23
|
+
}
|
|
24
|
+
if (config.policyDir == null) {
|
|
25
|
+
config.policyDir = "./Warden-RN";
|
|
26
|
+
}
|
|
27
|
+
if (config.dev == null) {
|
|
28
|
+
config.dev = true;
|
|
29
|
+
}
|
|
30
|
+
if (config.rootDir == null) {
|
|
31
|
+
config.rootDir = "./";
|
|
32
|
+
}
|
|
33
|
+
if (!serilaizer) {
|
|
34
|
+
serilaizer = (0, util_1.createDefaultMetroSerializer)();
|
|
35
|
+
}
|
|
36
|
+
return async (entryPoint, preModules, graph, options) => {
|
|
37
|
+
const rootDir = path.resolve(path.join(options.projectRoot, config.rootDir));
|
|
38
|
+
let sourceRoot = path.resolve(path.join(rootDir, config.sourceRoot));
|
|
39
|
+
if (!sourceRoot.endsWith(path.sep)) {
|
|
40
|
+
sourceRoot += path.sep;
|
|
41
|
+
}
|
|
42
|
+
const policyDir = path.resolve(path.join(rootDir), config.policyDir);
|
|
43
|
+
if (!(0, node_fs_1.existsSync)(policyDir)) {
|
|
44
|
+
(0, node_fs_1.mkdirSync)(policyDir);
|
|
45
|
+
}
|
|
46
|
+
const modifiedOptions = { ...options };
|
|
47
|
+
const createModuleId = options.createModuleId;
|
|
48
|
+
const moduleMap = new bimap_1.BiMap();
|
|
49
|
+
// 记录模块ID映射
|
|
50
|
+
modifiedOptions.createModuleId = (filePath) => {
|
|
51
|
+
const id = createModuleId(filePath);
|
|
52
|
+
moduleMap.set(id, filePath);
|
|
53
|
+
return id;
|
|
54
|
+
};
|
|
55
|
+
const serializerResult = serilaizer(entryPoint, preModules, graph, modifiedOptions);
|
|
56
|
+
const { code, map } = await (0, util_1.extractSerializerResult)(serializerResult);
|
|
57
|
+
if (options.dev) {
|
|
58
|
+
return { code, map };
|
|
59
|
+
}
|
|
60
|
+
const ast = (0, parser_1.parse)(code, {
|
|
61
|
+
sourceType: "module",
|
|
62
|
+
});
|
|
63
|
+
// 提取所有module信息
|
|
64
|
+
let override = undefined;
|
|
65
|
+
if ((0, node_fs_1.existsSync)(path.join(policyDir, "policy-override.json"))) {
|
|
66
|
+
console.log(`load override policy from ${path.join(policyDir, "policy-override.json")}`);
|
|
67
|
+
override = JSON.parse((0, node_fs_1.readFileSync)(path.join(policyDir, "policy-override.json"), "utf-8"));
|
|
68
|
+
}
|
|
69
|
+
const policy = new config_1.Policy(moduleMap, rootDir, override);
|
|
70
|
+
(0, traverse_1.default)(ast, {
|
|
71
|
+
Program(path) {
|
|
72
|
+
const bodyPaths = path.get("body");
|
|
73
|
+
for (const stm of bodyPaths) {
|
|
74
|
+
const stmt = stm.node;
|
|
75
|
+
if (t.isExpressionStatement(stmt) &&
|
|
76
|
+
t.isCallExpression(stmt.expression) &&
|
|
77
|
+
t.isIdentifier(stmt.expression.callee) &&
|
|
78
|
+
stmt.expression.callee.name === "__d") {
|
|
79
|
+
if (!t.isFunctionExpression(stmt.expression.arguments[0]) ||
|
|
80
|
+
!t.isNumericLiteral(stmt.expression.arguments[1]) ||
|
|
81
|
+
!t.isArrayExpression(stmt.expression.arguments[2])) {
|
|
82
|
+
console.warn(`[-] 跳过不规则的模块定义语句 - ${JSON.stringify(stmt.loc)}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const moduleFn = stmt.expression.arguments[0];
|
|
86
|
+
const moduleId = stmt.expression.arguments[1].value;
|
|
87
|
+
const moduleDeps = stmt.expression.arguments[2].elements.map((e) => e.value);
|
|
88
|
+
const moduleName = moduleMap.getByKey(moduleId);
|
|
89
|
+
if (moduleName == null) {
|
|
90
|
+
throw new Error(`unknown module id ${moduleId}`);
|
|
91
|
+
}
|
|
92
|
+
// 如果是一方模块, 跳过不处理
|
|
93
|
+
if (moduleName.startsWith(sourceRoot)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const moduleDepNames = moduleDeps.map((e) => {
|
|
97
|
+
const name = moduleMap.getByKey(e);
|
|
98
|
+
if (name == null) {
|
|
99
|
+
throw new Error(`unknown module id ${e}`);
|
|
100
|
+
}
|
|
101
|
+
return name;
|
|
102
|
+
});
|
|
103
|
+
const item = { deps: [], globals: {} };
|
|
104
|
+
item.deps = moduleDepNames;
|
|
105
|
+
item.globals = (0, globals_1.analyzeGlobals)(
|
|
106
|
+
//@ts-expect-error
|
|
107
|
+
stm.get("expression"), true);
|
|
108
|
+
policy.setModulePolicy(moduleId, item);
|
|
109
|
+
policy.loadOverride(moduleId);
|
|
110
|
+
(0, deps_1.protectRequire)(stm
|
|
111
|
+
.get("expression")
|
|
112
|
+
.get("arguments")[0], moduleDeps);
|
|
113
|
+
(0, globals_1.hardenGlobals)(stm.get("expression"), policy.getModulePolicy(moduleId).globals, moduleId, config.dev);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
path.stop();
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
(0, harden_1.addPrototypePollutionGuard)(ast);
|
|
120
|
+
const id2path = Object.create(null);
|
|
121
|
+
for (const [id, p] of moduleMap.entries()) {
|
|
122
|
+
id2path[id] = path.relative(rootDir, p);
|
|
123
|
+
}
|
|
124
|
+
(0, globals_1.refactorRuntime)(ast, id2path, config.dev);
|
|
125
|
+
const finalResult = await generateWithExistingMap(ast, code, JSON.parse(map));
|
|
126
|
+
(0, node_fs_1.writeFileSync)(path.join(policyDir, "policy.json"), policy.toJSON());
|
|
127
|
+
return { code: finalResult.code, map: finalResult.map };
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function generateWithExistingMap(ast, originalCode, originalMap) {
|
|
131
|
+
const hasMap = Object.keys(originalMap).length > 0;
|
|
132
|
+
// 生成新代码
|
|
133
|
+
const generated = (0, generator_1.default)(ast, {
|
|
134
|
+
sourceMaps: hasMap,
|
|
135
|
+
sourceFileName: hasMap ? "source.js" : undefined,
|
|
136
|
+
}, hasMap ? originalCode : undefined);
|
|
137
|
+
// 如果有原始 source map,需要合并
|
|
138
|
+
if (hasMap) {
|
|
139
|
+
const final = remapping([generated.map, originalMap], () => null);
|
|
140
|
+
return {
|
|
141
|
+
code: generated.code,
|
|
142
|
+
map: JSON.stringify(final),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
code: generated.code,
|
|
147
|
+
map: "{}",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class BiMap<K, V> {
|
|
2
|
+
private keyToValue;
|
|
3
|
+
private valueToKey;
|
|
4
|
+
constructor(entries?: readonly (readonly [K, V])[] | null);
|
|
5
|
+
set(key: K, value: V): this;
|
|
6
|
+
getByKey(key: K): V | undefined;
|
|
7
|
+
getByValue(value: V): K | undefined;
|
|
8
|
+
deleteByKey(key: K): boolean;
|
|
9
|
+
deleteByValue(value: V): boolean;
|
|
10
|
+
hasKey(key: K): boolean;
|
|
11
|
+
hasValue(value: V): boolean;
|
|
12
|
+
clear(): void;
|
|
13
|
+
get keys(): IterableIterator<K>;
|
|
14
|
+
get values(): IterableIterator<V>;
|
|
15
|
+
get size(): number;
|
|
16
|
+
entries(): IterableIterator<[K, V]>;
|
|
17
|
+
forEach(callback: (value: V, key: K, map: BiMap<K, V>) => void, thisArg?: any): void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=bimap.d.ts.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BiMap = void 0;
|
|
4
|
+
class BiMap {
|
|
5
|
+
keyToValue;
|
|
6
|
+
valueToKey;
|
|
7
|
+
constructor(entries) {
|
|
8
|
+
this.keyToValue = new Map();
|
|
9
|
+
this.valueToKey = new Map();
|
|
10
|
+
if (entries) {
|
|
11
|
+
for (const [key, value] of entries) {
|
|
12
|
+
this.set(key, value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// 设置键值对
|
|
17
|
+
set(key, value) {
|
|
18
|
+
// 检查键或值是否已存在
|
|
19
|
+
if (this.keyToValue.has(key)) {
|
|
20
|
+
const existingValue = this.keyToValue.get(key);
|
|
21
|
+
this.valueToKey.delete(existingValue);
|
|
22
|
+
}
|
|
23
|
+
if (this.valueToKey.has(value)) {
|
|
24
|
+
const existingKey = this.valueToKey.get(value);
|
|
25
|
+
this.keyToValue.delete(existingKey);
|
|
26
|
+
}
|
|
27
|
+
this.keyToValue.set(key, value);
|
|
28
|
+
this.valueToKey.set(value, key);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
// 通过键获取值
|
|
32
|
+
getByKey(key) {
|
|
33
|
+
return this.keyToValue.get(key);
|
|
34
|
+
}
|
|
35
|
+
// 通过值获取键
|
|
36
|
+
getByValue(value) {
|
|
37
|
+
return this.valueToKey.get(value);
|
|
38
|
+
}
|
|
39
|
+
// 删除指定键的映射
|
|
40
|
+
deleteByKey(key) {
|
|
41
|
+
if (!this.keyToValue.has(key)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const value = this.keyToValue.get(key);
|
|
45
|
+
this.keyToValue.delete(key);
|
|
46
|
+
this.valueToKey.delete(value);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
// 删除指定值的映射
|
|
50
|
+
deleteByValue(value) {
|
|
51
|
+
if (!this.valueToKey.has(value)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const key = this.valueToKey.get(value);
|
|
55
|
+
this.valueToKey.delete(value);
|
|
56
|
+
this.keyToValue.delete(key);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
// 检查是否包含键
|
|
60
|
+
hasKey(key) {
|
|
61
|
+
return this.keyToValue.has(key);
|
|
62
|
+
}
|
|
63
|
+
// 检查是否包含值
|
|
64
|
+
hasValue(value) {
|
|
65
|
+
return this.valueToKey.has(value);
|
|
66
|
+
}
|
|
67
|
+
// 清空所有映射
|
|
68
|
+
clear() {
|
|
69
|
+
this.keyToValue.clear();
|
|
70
|
+
this.valueToKey.clear();
|
|
71
|
+
}
|
|
72
|
+
// 获取所有键
|
|
73
|
+
get keys() {
|
|
74
|
+
return this.keyToValue.keys();
|
|
75
|
+
}
|
|
76
|
+
// 获取所有值
|
|
77
|
+
get values() {
|
|
78
|
+
return this.valueToKey.keys();
|
|
79
|
+
}
|
|
80
|
+
// 获取大小
|
|
81
|
+
get size() {
|
|
82
|
+
return this.keyToValue.size;
|
|
83
|
+
}
|
|
84
|
+
// 获取所有键值对
|
|
85
|
+
entries() {
|
|
86
|
+
return this.keyToValue.entries();
|
|
87
|
+
}
|
|
88
|
+
// 遍历所有键值对
|
|
89
|
+
forEach(callback, thisArg) {
|
|
90
|
+
this.keyToValue.forEach((value, key) => {
|
|
91
|
+
callback.call(thisArg, value, key, this);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.BiMap = BiMap;
|
|
96
|
+
//# sourceMappingURL=bimap.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BiMap } from "./bimap";
|
|
2
|
+
export type PolicyItem = {
|
|
3
|
+
globals: Record<string, "r" | "rw">;
|
|
4
|
+
deps: string[];
|
|
5
|
+
};
|
|
6
|
+
export type OverRidePolicy = Record<string, Record<string, "r" | "rw">>;
|
|
7
|
+
export declare class Policy {
|
|
8
|
+
private policy;
|
|
9
|
+
private moduleMap;
|
|
10
|
+
private rootDir;
|
|
11
|
+
private override;
|
|
12
|
+
constructor(moduleMap: BiMap<number, string>, rootDir: string, override?: OverRidePolicy | undefined);
|
|
13
|
+
getModulePolicy(moduleId: number): PolicyItem | undefined;
|
|
14
|
+
setModulePolicy(moduleId: number, policy: PolicyItem): void;
|
|
15
|
+
loadOverride(moduleId: number): void;
|
|
16
|
+
toJSON(): string;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Policy = void 0;
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
class Policy {
|
|
6
|
+
policy = Object.create(null);
|
|
7
|
+
moduleMap;
|
|
8
|
+
rootDir;
|
|
9
|
+
override;
|
|
10
|
+
constructor(moduleMap, rootDir, override = undefined) {
|
|
11
|
+
this.moduleMap = moduleMap;
|
|
12
|
+
this.rootDir = rootDir;
|
|
13
|
+
this.override = override;
|
|
14
|
+
}
|
|
15
|
+
getModulePolicy(moduleId) {
|
|
16
|
+
return this.policy[moduleId];
|
|
17
|
+
}
|
|
18
|
+
setModulePolicy(moduleId, policy) {
|
|
19
|
+
this.policy[moduleId] = policy;
|
|
20
|
+
}
|
|
21
|
+
loadOverride(moduleId) {
|
|
22
|
+
if (this.override == null) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const modulePath = this.moduleMap.getByKey(moduleId);
|
|
26
|
+
if (modulePath == null) {
|
|
27
|
+
throw new Error(`unknown module id: ${moduleId}`);
|
|
28
|
+
}
|
|
29
|
+
const key = path.relative(this.rootDir, modulePath);
|
|
30
|
+
if (this.override[key] == null) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
Object.assign(this.policy[moduleId].globals, this.override[key]);
|
|
34
|
+
}
|
|
35
|
+
toJSON() {
|
|
36
|
+
const newPolicy = Object.create(null);
|
|
37
|
+
const entries = Object.entries(this.policy).sort((a, b) => a[0].localeCompare(b[0]));
|
|
38
|
+
for (let [k, v] of entries) {
|
|
39
|
+
const modulePath = this.moduleMap.getByKey(parseInt(k));
|
|
40
|
+
if (modulePath == null) {
|
|
41
|
+
throw new Error(`unknown module id: ${k}`);
|
|
42
|
+
}
|
|
43
|
+
v = structuredClone(v);
|
|
44
|
+
v.deps = v.deps
|
|
45
|
+
.map((e) => path.relative(this.rootDir, e))
|
|
46
|
+
.sort((a, b) => a.localeCompare(b));
|
|
47
|
+
v.globals = Object.keys(v.globals)
|
|
48
|
+
.sort()
|
|
49
|
+
.reduce((acc, key) => {
|
|
50
|
+
acc[key] = v.globals[key];
|
|
51
|
+
return acc;
|
|
52
|
+
}, {});
|
|
53
|
+
newPolicy[path.relative(this.rootDir, modulePath)] = v;
|
|
54
|
+
}
|
|
55
|
+
return JSON.stringify(newPolicy, null, 4);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.Policy = Policy;
|
|
59
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates the default Metro plain bundle serializer.
|
|
3
|
+
* Because Metro exports only the intermediate serializer functions, we need to
|
|
4
|
+
* assemble the final serializer ourselves. We have to work with the modules the same as Metro does
|
|
5
|
+
* to avoid unexpected changes in the final bundle.
|
|
6
|
+
*
|
|
7
|
+
* This is used when the user does not provide a custom serializer.
|
|
8
|
+
*
|
|
9
|
+
* https://github.com/facebook/metro/blob/9b85f83c9cc837d8cd897aa7723be7da5b296067/packages/metro/src/Server.js#L244-L277
|
|
10
|
+
*/
|
|
11
|
+
export declare const createDefaultMetroSerializer: () => (entryPoint: any, preModules: any, graph: any, options: any) => any;
|
|
12
|
+
export declare function extractSerializerResult(serializerResult: any): Promise<{
|
|
13
|
+
code: any;
|
|
14
|
+
map: any;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDefaultMetroSerializer = void 0;
|
|
4
|
+
exports.extractSerializerResult = extractSerializerResult;
|
|
5
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
6
|
+
//@ts-nocheck
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const metroPath = path.dirname(require.resolve("metro/package.json"));
|
|
9
|
+
const baseJSBundlePath = path.join(metroPath, "src", "DeltaBundler", "Serializers", "baseJSBundle.js");
|
|
10
|
+
const sourceMapStringPath = path.join(metroPath, "src", "DeltaBundler", "Serializers", "sourceMapString.js");
|
|
11
|
+
const bundleToStringPath = path.join(metroPath, "src", "lib", "bundleToString.js");
|
|
12
|
+
const baseJSBundle = require(baseJSBundlePath).default;
|
|
13
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
14
|
+
const sourceMapString = require(sourceMapStringPath);
|
|
15
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
16
|
+
const bundleToString = require(bundleToStringPath).default;
|
|
17
|
+
/**
|
|
18
|
+
* This function ensures that modules in source maps are sorted in the same
|
|
19
|
+
* order as in a plain JS bundle.
|
|
20
|
+
*
|
|
21
|
+
* https://github.com/facebook/metro/blob/9b85f83c9cc837d8cd897aa7723be7da5b296067/packages/metro/src/Server.js#L984
|
|
22
|
+
*/
|
|
23
|
+
const getSortedModules = (graph, { createModuleId }) => {
|
|
24
|
+
const modules = [...graph.dependencies.values()];
|
|
25
|
+
// Sort by IDs
|
|
26
|
+
return modules.sort((a, b) => createModuleId(a.path) - createModuleId(b.path));
|
|
27
|
+
};
|
|
28
|
+
exports.getSortedModules = getSortedModules;
|
|
29
|
+
/**
|
|
30
|
+
* Creates the default Metro plain bundle serializer.
|
|
31
|
+
* Because Metro exports only the intermediate serializer functions, we need to
|
|
32
|
+
* assemble the final serializer ourselves. We have to work with the modules the same as Metro does
|
|
33
|
+
* to avoid unexpected changes in the final bundle.
|
|
34
|
+
*
|
|
35
|
+
* This is used when the user does not provide a custom serializer.
|
|
36
|
+
*
|
|
37
|
+
* https://github.com/facebook/metro/blob/9b85f83c9cc837d8cd897aa7723be7da5b296067/packages/metro/src/Server.js#L244-L277
|
|
38
|
+
*/
|
|
39
|
+
const createDefaultMetroSerializer = () => {
|
|
40
|
+
return (entryPoint, preModules, graph, options) => {
|
|
41
|
+
// baseJSBundle assigns IDs to modules in a consistent order
|
|
42
|
+
let bundle = baseJSBundle(entryPoint, preModules, graph, options);
|
|
43
|
+
if (options.sentryBundleCallback && !graph.transformOptions.hot) {
|
|
44
|
+
bundle = options.sentryBundleCallback(bundle);
|
|
45
|
+
}
|
|
46
|
+
const { code } = bundleToString(bundle);
|
|
47
|
+
if (graph.transformOptions.hot) {
|
|
48
|
+
// Hot means running in dev server, sourcemaps are generated on demand
|
|
49
|
+
return code;
|
|
50
|
+
}
|
|
51
|
+
let sourceMapStringFunction;
|
|
52
|
+
if (typeof sourceMapString === "function") {
|
|
53
|
+
sourceMapStringFunction = sourceMapString;
|
|
54
|
+
}
|
|
55
|
+
else if (typeof sourceMapString === "object" &&
|
|
56
|
+
sourceMapString != null &&
|
|
57
|
+
"sourceMapString" in sourceMapString &&
|
|
58
|
+
typeof sourceMapString["sourceMapString"] === "function") {
|
|
59
|
+
sourceMapStringFunction = sourceMapString.sourceMapString;
|
|
60
|
+
}
|
|
61
|
+
else if (typeof sourceMapString?.default === "function") {
|
|
62
|
+
sourceMapStringFunction = sourceMapString.default;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw new Error(`Cannot find sourceMapString function in 'metro/src/DeltaBundler/Serializers/sourceMapString'`);
|
|
66
|
+
}
|
|
67
|
+
// Always generate source maps, can't use Sentry without source maps
|
|
68
|
+
const map = sourceMapStringFunction([...preModules, ...(0, exports.getSortedModules)(graph, options)], {
|
|
69
|
+
processModuleFilter: options.processModuleFilter,
|
|
70
|
+
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
|
|
71
|
+
});
|
|
72
|
+
return { code, map };
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
exports.createDefaultMetroSerializer = createDefaultMetroSerializer;
|
|
76
|
+
async function extractSerializerResult(serializerResult) {
|
|
77
|
+
if (typeof serializerResult === "string") {
|
|
78
|
+
return { code: serializerResult, map: "{}" };
|
|
79
|
+
}
|
|
80
|
+
if ("map" in serializerResult) {
|
|
81
|
+
return { code: serializerResult.code, map: serializerResult.map };
|
|
82
|
+
}
|
|
83
|
+
const awaitedResult = await serializerResult;
|
|
84
|
+
if (typeof awaitedResult === "string") {
|
|
85
|
+
return { code: awaitedResult, map: "{}" };
|
|
86
|
+
}
|
|
87
|
+
return { code: awaitedResult.code, map: awaitedResult.map };
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=util.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "warden.rn",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/**/*.js",
|
|
11
|
+
"dist/**/*.d.ts"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"type": "commonjs",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/babel__generator": "^7.27.0",
|
|
19
|
+
"@types/babel__traverse": "^7.28.0",
|
|
20
|
+
"@types/node": "^25.0.3",
|
|
21
|
+
"metro": "^0.83.3"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@ampproject/remapping": "^2.3.0",
|
|
25
|
+
"@babel/generator": "^7.28.5",
|
|
26
|
+
"@babel/parser": "^7.28.5",
|
|
27
|
+
"@babel/traverse": "^7.28.5",
|
|
28
|
+
"@babel/types": "^7.28.5"
|
|
29
|
+
}
|
|
30
|
+
}
|