forked from gm-vm/openfortivpn-webview
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
196 lines (172 loc) · 5.86 KB
/
index.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
const { app, BrowserWindow, session, Menu } = require('electron');
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const { Console } = require('console');
const errorConsole = new Console(process.stderr);
const defaultUrlRegex = '/sslvpn/portal\\.html';
const cookieName = 'SVPNCOOKIE';
const parser = yargs(hideBin(process.argv))
.command('[host:port]', 'Connect to the given host')
.option('realm', {
describe: 'The authentication realm.',
type: "string",
})
.option('url', {
describe: 'The already built SAML URL. This takes precedence over [host:port].',
type: "string",
})
.option('url-regex', {
describe: "A regex to detect the URL that needs to be visited before printing SVPNCOOKIE.",
type: "string",
default: defaultUrlRegex,
})
.option('keep-open', {
describe: 'Do not close the browser automatically.',
})
.option('proxy-server', {
describe: 'HTTP Proxy in the format hostname:port.',
type: "string",
})
.option('extra-ca-certs', {
describe: 'Path to a file with extra certificates. The file should consist of one or more trusted certificates in PEM format.',
type: "string",
})
.option('trusted-cert', {
describe: 'The fingerprint of a certificate to always trust, even if invalid. The details of invalid certificates, fingerprint included, will be dumped in the console.',
type: "string",
})
.help();
const argv = parser.parse();
if (argv._.length == 0 && !argv.url) {
parser.showHelp()
process.exit(1);
}
const urlBuilder = () => {
if (argv.url) {
return argv.url;
} else {
const realm = argv.realm ? `?realm=${argv.realm}` : '';
return `https://${argv._[0]}/remote/saml/start${realm}`;
}
};
const urlRegex = RegExp(argv['url-regex'] ? argv['url-regex'] : defaultUrlRegex);
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
if (argv['trusted-cert'] === certificate.fingerprint) {
event.preventDefault();
callback(true);
} else {
errorConsole.error('Found an invalid certificate:');
errorConsole.dir(certificate, { depth: null });
errorConsole.error();
errorConsole.error('If you know that this certificate can be trusted, relaunch the application passing the following argument to ignore the error:');
errorConsole.error(`--trusted-cert='${certificate.fingerprint}'`);
process.exit(1);
}
})
if (argv['extra-ca-certs']) {
const pemHeader = '-----BEGIN CERTIFICATE-----';
const pemFooter = '-----END CERTIFICATE-----';
// The binary representation allows to easily compare certificates that use different line-endings.
let pemToBytes = pem => {
const start = pem.indexOf(pemHeader) + pemHeader.length;
const end = pem.indexOf(pemFooter);
return atob(pem.substring(start, end));
}
try {
const fileContent = require('fs').readFileSync(argv['extra-ca-certs'], 'utf8');
const certExtractionRegex = new RegExp(`${pemHeader}[^-]+${pemFooter}`, 'g');
const extraCaCerts = new Set(fileContent.match(certExtractionRegex).map(pem => pemToBytes(pem)));
let issuerPem = certificate => {
// issuerCert of self-signed certificates is undefined.
return certificate.issuerCert ? certificate.issuerCert.data : certificate.data;
}
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
if (
error === 'net::ERR_CERT_AUTHORITY_INVALID' &&
extraCaCerts.has(pemToBytes(issuerPem(certificate)))
) {
event.preventDefault();
callback(true);
} else {
callback(false);
}
});
} catch (e) {
errorConsole.error(e.message);
process.exit(1);
}
}
app.whenReady().then(() => {
const window = new BrowserWindow({ width: 800, height: 600 });
var shouldPrintCookie = false;
var svpncookie = null;
const tryPrintCookie = () => {
if (shouldPrintCookie && svpncookie != null) {
process.stdout.write(`${cookieName}=${svpncookie}\n`);
if (!argv['keep-open']) {
process.exit(0);
}
}
}
window.webContents.on('did-start-navigation', (e, url) => {
process.stderr.write(url + '\n');
if (urlRegex.test(url)) {
shouldPrintCookie = true;
tryPrintCookie();
}
});
session.defaultSession.cookies.on('changed', (e, cookie) => {
if (cookie.name == cookieName) {
svpncookie = cookie.value;
tryPrintCookie();
}
});
window.on('close', function() {
process.exit(argv['keep-open'] ? 0 : 1);
});
['did-fail-load', 'did-fail-provisional-load'].forEach(event => {
window.webContents.on(event, (e, errorCode, errorDescription, validatedURL) => {
process.stderr.write(`Failed to load ${validatedURL}: ${errorCode} ${errorDescription}\n`);
process.exit(1);
});
});
window.on('close', function() {
process.exit(argv['keep-open'] ? 0 : 1);
});
const menu = Menu.buildFromTemplate([{
label: "File",
submenu: [
{
role: "reload",
},
{
type: "separator",
},
{
label: "Clear data",
click: () => { session.defaultSession.clearStorageData() },
},
{
type: "separator",
},
{
label: 'Quit App',
accelerator: 'CmdOrCtrl+Q',
click: () => { app.quit() },
},
]
},{
label: "Edit",
submenu: [
{ label: "Undo", accelerator: "CmdOrCtrl+Z", role: "undo" },
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", role: "redo" },
{ type: "separator" },
{ label: "Cut", accelerator: "CmdOrCtrl+X", role: "cut" },
{ label: "Copy", accelerator: "CmdOrCtrl+C", role: "copy" },
{ label: "Paste", accelerator: "CmdOrCtrl+V", role: "paste" },
{ label: "Select All", accelerator: "CmdOrCtrl+A", role: "selectAll" },
]
}]);
Menu.setApplicationMenu(menu);
window.loadURL(urlBuilder());
});