Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/mitm-socket/install.js
1028 views
1
const { execSync } = require('child_process');
2
const fs = require('fs');
3
const os = require('os');
4
const { httpGet } = require('@secret-agent/commons/downloadFile');
5
const { createHash } = require('crypto');
6
const { gunzipSync } = require('zlib');
7
const packageJson = require('./package.json');
8
9
const outDir = `${__dirname}/dist`;
10
11
if (!fs.existsSync(outDir)) {
12
fs.mkdirSync(outDir);
13
}
14
const { version } = packageJson;
15
const releasesAssetsUrl = `https://github.com/ulixee/secret-agent/releases/download/v${version}`;
16
17
// tslint:disable:no-console
18
19
const forceBuild = Boolean(JSON.parse(process.env.SA_REBUILD_MITM_SOCKET || 'false'));
20
21
(async function install() {
22
let programName = 'connect';
23
const filename = buildFilename();
24
if (os.platform() === 'win32') {
25
programName += '.exe';
26
}
27
28
const installed = getInstalledVersion();
29
if (!forceBuild && installed && installed.startsWith(version) && isBinaryInstalled(programName)) {
30
console.log('Latest SecretAgent connect library already installed');
31
process.exit(0);
32
}
33
34
const checksum = await getSourceChecksum(filename);
35
const filepath = `${releasesAssetsUrl}/${filename}`;
36
37
if (!checksum) {
38
if (tryBuild(programName)) {
39
saveVersion();
40
console.log('Successfully compiled Secret Agent connect library');
41
process.exit(0);
42
}
43
44
const goVersionNeeded = getGoVersionNeeded();
45
console.log(
46
`The architecture file you need for the Secret Agent connect library is not available (${filepath}).\n\n
47
You can install golang ${goVersionNeeded} (https://golang.org/) and run "go build" from the mitm-socket/go directory\n\n`,
48
);
49
process.exit(1);
50
}
51
52
console.log('Downloading Secret Agent connect library from %s (checksum=%s)', filepath, checksum);
53
const zippedFile = await download(filepath);
54
55
const downloadedChecksum = getFileChecksum(zippedFile);
56
if (downloadedChecksum !== checksum) {
57
console.log('WARN!! Checksum mismatch for the Secret Agent connect library', {
58
checksum,
59
downloadedChecksum,
60
});
61
process.exit(1);
62
}
63
64
const file = gunzipSync(zippedFile);
65
66
fs.writeFileSync(`${outDir}/${programName}`, file);
67
fs.chmodSync(`${outDir}/${programName}`, 0o755);
68
saveVersion();
69
console.log('Successfully downloaded');
70
process.exit(0);
71
})().catch(err => {
72
console.log('Could not install MitmSocket library', err);
73
process.exit(1);
74
});
75
76
function tryBuild(programName) {
77
const goVersionNeeded = getGoVersionNeeded();
78
const isGoInstalled = isGoVersionInstalled(goVersionNeeded);
79
console.log('Is go installed? %s, %s', goVersionNeeded, isGoInstalled);
80
81
if (isGoInstalled) {
82
if (compile()) {
83
fs.renameSync(`${__dirname}/go/${programName}`, `${outDir}/${programName}`);
84
return true;
85
}
86
}
87
return false;
88
}
89
90
function getInstalledVersion() {
91
if (fs.existsSync(`${outDir}/version`)) {
92
return fs.readFileSync(`${outDir}/version`, 'utf8');
93
}
94
return null;
95
}
96
97
function isBinaryInstalled(programName) {
98
return fs.existsSync(`${outDir}/${programName}`);
99
}
100
101
function saveVersion() {
102
fs.writeFileSync(`${outDir}/version`, version);
103
}
104
105
function buildFilename() {
106
let platform = String(os.platform());
107
let arch = os.arch();
108
if (arch === 'x64') arch = 'x86_64';
109
if (arch === 'ia32') arch = 'i386';
110
111
if (platform === 'win32') {
112
platform = 'win';
113
}
114
if (platform === 'darwin') {
115
platform = 'mac';
116
}
117
118
return `connect_${version}_${platform}_${arch}.gz`;
119
}
120
121
function download(filepath) {
122
return new Promise((resolve, reject) => {
123
const req = httpGet(filepath, async res => {
124
if (res.statusCode >= 400) {
125
return reject(
126
new Error(
127
`ERROR downloading needed Secret Agent library - ${res.statusCode}:${res.statusMessage}`,
128
),
129
);
130
}
131
132
try {
133
const buffer = [];
134
for await (const chunk of res) {
135
buffer.push(chunk);
136
}
137
const output = Buffer.concat(buffer);
138
resolve(output);
139
} catch (err) {
140
reject(err);
141
}
142
});
143
req.on('error', err => {
144
console.log('ERROR downloading needed Secret Agent library %s', filepath, err);
145
reject(err);
146
});
147
});
148
}
149
150
function getFileChecksum(file) {
151
return createHash('sha256').update(file).digest().toString('hex');
152
}
153
154
async function getSourceChecksum(filename) {
155
if (forceBuild) return null;
156
const buffer = await download(`${releasesAssetsUrl}/connect.checksum`);
157
158
const checksum = buffer.toString('utf8');
159
160
const match = checksum.split(/\r?\n/).find(x => x.endsWith(filename));
161
162
const expectedChecksum = match ? match.split(/\s+/).shift() : undefined;
163
164
if (!expectedChecksum) {
165
throw new Error('Invalid checksum found for Secret Agent MitmSocket library');
166
}
167
168
return expectedChecksum;
169
}
170
171
/////// /// GO BUILD ////////////////////////////////////////////////////////////////////////////////
172
173
function compile() {
174
try {
175
execSync('go build', { cwd: `${__dirname}/go` });
176
return true;
177
} catch (err) {
178
console.log(
179
'Error compiling Secret Agent MitmSocket library.\n\nWill download instead.',
180
err.message,
181
);
182
return false;
183
}
184
}
185
186
function getGoVersionNeeded() {
187
const goMod = fs.readFileSync(`${__dirname}/go/go.mod`, 'utf8');
188
const goMatch = goMod.match(/go ([\d.]+)/);
189
return goMatch[1];
190
}
191
192
function isGoVersionInstalled(wantedVersion) {
193
const goVersionNeeded = wantedVersion.split('.');
194
try {
195
const goVersionResult = execSync('go version', { encoding: 'utf8' });
196
const goVersion = goVersionResult.match(/go version go([\d.]+)\s\w+\/\w+/);
197
if (!goVersion || !goVersion.length) return false;
198
if (goVersion && goVersion.length) {
199
const versionParts = goVersion[1].split('.');
200
if (versionParts[0] !== goVersionNeeded[0]) return false;
201
if (parseInt(versionParts[1], 10) < parseInt(goVersionNeeded[1], 10)) return false;
202
return true;
203
}
204
} catch (err) {
205
return false;
206
}
207
}
208
209