-
Notifications
You must be signed in to change notification settings - Fork 1
/
static.js
139 lines (130 loc) · 4.53 KB
/
static.js
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
const util = require('./util');
const http = require('http');
const https = require('https');
/**
* Since an application's browser JS files are structured differently in
* development and production (many individual files versus a single minified
* bundle), the most simplest way to scan through the client-side JS is to pull
* down every JS file referenced from the app's index pgae.
**/
async function getJsUrls(baseUrl) {
try {
let homePage = await util.getUrl(baseUrl);
return [...homePage.matchAll(/<script[^>]+src="([^"]+)"[^>]*>/gm)].map((x) => x[1]);
} catch (e) {
console.error(e);
return [];
}
}
async function scanAllJs(baseUrl) {
if (baseUrl[baseUrl.length - 1] != '/') {
baseUrl += '/';
}
let data = {
'call': [],
'method': [],
'subscribe': [],
'publish': [],
'pkg': []
};
let urls = await getJsUrls(baseUrl);
for (let i = 0; i < urls.length; ++i) {
let u = urls[i];
if (u[0] == '/') {
u = u.substring(1);
}
let fileText = await util.getUrl(baseUrl + u);
data.call = data.call.concat(await findFunctionCalls('Meteor.call', fileText, u));
data.method = data.method.concat(await findFunctionCalls('Meteor.method', fileText, u));
data.subscribe = data.subscribe.concat(await findFunctionCalls('Meteor.subscribe', fileText, u));
data.publish = data.publish.concat(await findFunctionCalls('Meteor.publish', fileText, u));
data.pkg = data.pkg.concat(await findFunctionCalls('Package._define', fileText, u));
}
data.call = Array.from(new Set(data.call)).sort();
data.method = Array.from(new Set(data.method)).sort();
data.subscribe = Array.from(new Set(data.subscribe)).sort();
data.publish = Array.from(new Set(data.publish)).sort();
data.pkg = Array.from(new Set(data.pkg)).sort();
return data;
}
function findFunctionCalls(func, data, filename) {
let finds = [];
let re = new RegExp(func + "\\((['\"])([^'\"]+)\\1", 'gi');
data.split("\n").forEach((line, idx) => {
let matches = [...line.matchAll(re)];
matches.forEach((m) => {
util.errlog1(filename + " line " + idx + " char " + m.index + ", found " + m[0] + " " + m[2]);
finds.push(m[2]);
});
});
return finds;
}
/**
* Given the base URL of a meteor app, download the app's main client-side JS
* bundle (app.js) and search for calls to methods on the Meteor global object
* that reveal the names of publications or methods. This function dumps them
* to stdout. TODO: return the data and let ehf.js generate the output.
**/
async function searchJsFile(data, filename) {
let lines = data.split("\n").map((x, index) => ({line: x.trim(), index: index}));
let lineOutput = (x) => "app.js:" + x.index + ":" + x.line;
let stringFilter = (lines, probe) => lines.filter((x, idx) => x.line.includes(probe))
.map({'location':filename+':'+idx, 'text':lineOutput});
return {
'call': stringFilter(lines, "Meteor.call"),
'method': stringFilter(lines, "Meteor.methods"),
'subscribe': stringFilter(lines, "Meteor.subscribe"),
'publish': stringFilter(lines, "Meteor.publish")
};
/*
if ((callLines + methodLines).length > 0) {
console.log("-------- METHODS --------");
if (callLines.length > 0) {
console.log("Client-side definitions:");
console.log(callLines.join("\n"));
}
if (methodLines.length > 0) {
console.log("Server-side definitions:");
console.log(methodLines.join("\n"));
}
}
if ((subscribeLines + publishLines).length > 0) {
console.log("------ PUBLICATIONS -----");
if (subscribeLines.length > 0) {
console.log("Client-side definitions:");
console.log(subscribeLines.join("\n"));
}
if (publishLines.length > 0) {
console.log("Server-side definitions:");
console.log(publishLines.join("\n"));
}
}
});
let handle = (response) => {
let body = '';
response.on('data', (part) => body += part);
response.on('end', () => { next(body); });
response.on('error', (e) => { console.error(e); });
};
pkg.get(url, handle);
*/
};
module.exports = {scanAllJs};
function main() {
let p = scanAllJs(process.argv[2]);
console.log(p);
p.then((x) => {
console.log("Resolved!");
console.log(x);
});
console.log("Thenned");
/*
console.log("OUTCOME");
let p = scanAllJs(process.argv[2]);
console.log(p);
p.then((x) => {
console.log("ResolveD");
});
*/
}
//main();