gologin 3.0.7 → 3.0.8
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/CHANGELOG.md +6 -0
- package/index.d.ts +1 -0
- package/package.json +2 -2
- package/src/gologin.js +14 -0
- package/src/utils/launch-arguments.js +83 -0
- package/test/unit/launch-arguments.test.js +96 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Combined changelog for GoLogin node.js SDK
|
|
4
4
|
|
|
5
|
+
## [3.0.8] 2026-11-12
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* Added `isCloudBrowser` option for GoLogin cloud browser. When enabled, profile `launchArguments` that run other programs (`*-cmd-prefix`, `*-launcher`, `--browser-subprocess-path`), open remote debugging, override the proxy or DNS, or point at paths (`--user-data-dir`, `--load-extension`, ...) are dropped and logged with proxy values redacted. Off by default; local launches are unchanged
|
|
10
|
+
|
|
5
11
|
## [3.0.7] 2026-10-15
|
|
6
12
|
|
|
7
13
|
### Fixes
|
package/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gologin",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.8",
|
|
4
4
|
"description": "A high-level API to control Orbita browser over GoLogin API",
|
|
5
5
|
"types": "./index.d.ts",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"test": "npm run test:unit && npm run test:e2e",
|
|
62
|
-
"test:unit": "
|
|
62
|
+
"test:unit": "node --test 'test/unit/*.test.js'",
|
|
63
63
|
"test:e2e": "node test/e2e/run-tests.js",
|
|
64
64
|
"test:e2e:local": "HEADLESS=false npm run test:e2e",
|
|
65
65
|
"format": "npx prettier --single-quote src/* --write",
|
package/src/gologin.js
CHANGED
|
@@ -15,6 +15,7 @@ import { checkAutoLang, getIntlProfileConfig, securedOrbitaOpts } from './utils/
|
|
|
15
15
|
import { API_URL, ensureDirectoryExists, FALLBACK_API_URL, getOsAdvanced } from './utils/common.js';
|
|
16
16
|
import { STORAGE_GATEWAY_BASE_URL } from './utils/constants.js';
|
|
17
17
|
import { checkSocksProxy, makeRequest } from './utils/http.js';
|
|
18
|
+
import { describeBlockedArgument, filterCloudLaunchArguments } from './utils/launch-arguments.js';
|
|
18
19
|
import {
|
|
19
20
|
// ensureSentryInitialized,
|
|
20
21
|
loadBrowserChecker,
|
|
@@ -69,6 +70,7 @@ export class GoLogin {
|
|
|
69
70
|
this.isFirstSession = false;
|
|
70
71
|
this.keepIndexedDb = false;
|
|
71
72
|
this.isCloudHeadless = options.isCloudHeadless ?? true;
|
|
73
|
+
this.isCloudBrowser = options.isCloudBrowser ?? false;
|
|
72
74
|
this.storageGatewayUrl = `${STORAGE_GATEWAY_BASE_URL}/upload`;
|
|
73
75
|
|
|
74
76
|
this.tmpdir = tmpdir();
|
|
@@ -494,6 +496,17 @@ export class GoLogin {
|
|
|
494
496
|
|
|
495
497
|
this.keepIndexedDb = profile.storage?.indexedDb === true;
|
|
496
498
|
this.profileLaunchArguments = (profile.launchArguments || '').split(' ').filter(Boolean);
|
|
499
|
+
if (this.isCloudBrowser && this.profileLaunchArguments.length) {
|
|
500
|
+
const { allowed, blocked } = filterCloudLaunchArguments(this.profileLaunchArguments);
|
|
501
|
+
if (blocked.length) {
|
|
502
|
+
console.warn('[launch-arguments] cloud browser: dropped profile launch arguments', {
|
|
503
|
+
profileId: this.profile_id,
|
|
504
|
+
blocked: blocked.map(describeBlockedArgument),
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
this.profileLaunchArguments = allowed;
|
|
509
|
+
}
|
|
497
510
|
|
|
498
511
|
const { navigator = {}, fonts, os: profileOs } = profile;
|
|
499
512
|
this.fontsMasking = fonts?.enableMasking;
|
|
@@ -629,6 +642,7 @@ export class GoLogin {
|
|
|
629
642
|
} else {
|
|
630
643
|
this.browserLang = checkAutoLangResult;
|
|
631
644
|
}
|
|
645
|
+
|
|
632
646
|
const prefsToWrite = Object.assign(preferences, { gologin });
|
|
633
647
|
if (this.customChromeFrame === false) {
|
|
634
648
|
prefsToWrite.browser = {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Profile launch arguments (profile.launchArguments) are free text set by the user and
|
|
2
|
+
// appended to Orbita's command line. In GoLogin's cloud browser that command line runs
|
|
3
|
+
// on our servers, so some switches must not come from the user:
|
|
4
|
+
// - switches that make Chrome run another program in place of its own processes
|
|
5
|
+
// (with --no-sandbox that is arbitrary command execution inside the pod),
|
|
6
|
+
// - remote debugging / DevTools access, which the cloud sets up itself,
|
|
7
|
+
// - proxy and DNS overrides, which would bypass the profile's proxy,
|
|
8
|
+
// - filesystem paths (profile dir, cache, logs, extensions loaded from a path).
|
|
9
|
+
// Chrome uses the last value of a repeated switch, so a user switch would also override
|
|
10
|
+
// the SDK's own. Only applied when the SDK runs with isCloudBrowser: true.
|
|
11
|
+
|
|
12
|
+
const BLOCKED_SWITCHES = new Set([
|
|
13
|
+
'browser-subprocess-path',
|
|
14
|
+
'type',
|
|
15
|
+
'remote-debugging-port',
|
|
16
|
+
'remote-debugging-pipe',
|
|
17
|
+
'remote-debugging-address',
|
|
18
|
+
'remote-debugging-io-pipes',
|
|
19
|
+
'remote-debugging-targets',
|
|
20
|
+
'remote-allow-origins',
|
|
21
|
+
'proxy-server',
|
|
22
|
+
'proxy-pac-url',
|
|
23
|
+
'no-proxy-server',
|
|
24
|
+
'proxy-bypass-list',
|
|
25
|
+
'proxy-auto-detect',
|
|
26
|
+
'host-resolver-rules',
|
|
27
|
+
'host-rules',
|
|
28
|
+
'user-data-dir',
|
|
29
|
+
'disk-cache-dir',
|
|
30
|
+
'crash-dumps-dir',
|
|
31
|
+
'log-file',
|
|
32
|
+
'load-extension',
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
// Any switch that wraps or replaces a child process launch:
|
|
36
|
+
// --renderer-cmd-prefix, --utility-cmd-prefix, --gpu-launcher, --ppapi-plugin-launcher, ...
|
|
37
|
+
const BLOCKED_SWITCH_PATTERNS = [/-cmd-prefix$/, /-launcher$/, /^nacl-gdb/];
|
|
38
|
+
|
|
39
|
+
// Chrome on Linux accepts both "--name" and "-name"; switch names are case-sensitive
|
|
40
|
+
// there, but lowercase them so no spelling slips through.
|
|
41
|
+
export const launchSwitchName = (arg) => {
|
|
42
|
+
const match = /^--?([^=]+)/.exec(arg);
|
|
43
|
+
|
|
44
|
+
return match ? match[1].trim().toLowerCase() : null;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const isBlockedSwitch = (name) =>
|
|
48
|
+
BLOCKED_SWITCHES.has(name) || BLOCKED_SWITCH_PATTERNS.some((pattern) => pattern.test(name));
|
|
49
|
+
|
|
50
|
+
// Returns the arguments that may be passed to Chrome and the ones that were removed.
|
|
51
|
+
// A bare "--" is removed too: Chrome would treat every argument after it, including the
|
|
52
|
+
// SDK's own switches, as a URL.
|
|
53
|
+
export const filterCloudLaunchArguments = (args) => {
|
|
54
|
+
const allowed = [];
|
|
55
|
+
const blocked = [];
|
|
56
|
+
for (const arg of args) {
|
|
57
|
+
if (arg === '--') {
|
|
58
|
+
blocked.push(arg);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const name = launchSwitchName(arg);
|
|
63
|
+
if (name !== null && isBlockedSwitch(name)) {
|
|
64
|
+
blocked.push(arg);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
allowed.push(arg);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { allowed, blocked };
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// For logs: keep what was tried (e.g. which program a *-cmd-prefix pointed at), but not
|
|
75
|
+
// proxy credentials.
|
|
76
|
+
export const describeBlockedArgument = (arg) => {
|
|
77
|
+
const name = launchSwitchName(arg);
|
|
78
|
+
if (name && /proxy|host-rules|host-resolver-rules/.test(name) && arg.includes('=')) {
|
|
79
|
+
return `${arg.slice(0, arg.indexOf('='))}=<redacted>`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return arg;
|
|
83
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
describeBlockedArgument,
|
|
6
|
+
filterCloudLaunchArguments,
|
|
7
|
+
launchSwitchName,
|
|
8
|
+
} from '../../src/utils/launch-arguments.js';
|
|
9
|
+
|
|
10
|
+
// The arguments seen on profile 6aebd85725714ca1d36e3531 (2026-11-12).
|
|
11
|
+
const SEEN_IN_CLOUD = [
|
|
12
|
+
'--load-extension=/home/neko/.gologin/extensions/user-extensions/glpextkeepalive000000000001',
|
|
13
|
+
'--utility-cmd-prefix=/usr/bin/python3',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
test('drops the arguments seen in the cloud', () => {
|
|
17
|
+
const { allowed, blocked } = filterCloudLaunchArguments(SEEN_IN_CLOUD);
|
|
18
|
+
assert.deepEqual(allowed, []);
|
|
19
|
+
assert.deepEqual(blocked, SEEN_IN_CLOUD);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('drops every switch that runs another program', () => {
|
|
23
|
+
const args = [
|
|
24
|
+
'--renderer-cmd-prefix=/bin/sh -c id',
|
|
25
|
+
'--utility-cmd-prefix=/usr/bin/python3',
|
|
26
|
+
'--gpu-cmd-prefix=x',
|
|
27
|
+
'--zygote-cmd-prefix=x',
|
|
28
|
+
'--gpu-launcher=/bin/sh',
|
|
29
|
+
'--plugin-launcher=x',
|
|
30
|
+
'--ppapi-plugin-launcher=x',
|
|
31
|
+
'--browser-subprocess-path=/tmp/x',
|
|
32
|
+
'--nacl-gdb=/tmp/x',
|
|
33
|
+
'--nacl-gdb-script=/tmp/x',
|
|
34
|
+
'--type=renderer',
|
|
35
|
+
];
|
|
36
|
+
assert.deepEqual(filterCloudLaunchArguments(args).allowed, []);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('drops remote debugging, proxy, DNS and path overrides', () => {
|
|
40
|
+
const args = [
|
|
41
|
+
'--remote-debugging-port=9222',
|
|
42
|
+
'--remote-debugging-address=0.0.0.0',
|
|
43
|
+
'--remote-debugging-pipe',
|
|
44
|
+
'--remote-allow-origins=*',
|
|
45
|
+
'--proxy-server=http://user:pass@1.2.3.4:8080',
|
|
46
|
+
'--proxy-pac-url=http://x/pac',
|
|
47
|
+
'--no-proxy-server',
|
|
48
|
+
'--proxy-bypass-list=*',
|
|
49
|
+
'--host-resolver-rules=MAP * 1.2.3.4',
|
|
50
|
+
'--host-rules=MAP * 1.2.3.4',
|
|
51
|
+
'--user-data-dir=/tmp/other',
|
|
52
|
+
'--disk-cache-dir=/tmp/c',
|
|
53
|
+
'--crash-dumps-dir=/tmp/d',
|
|
54
|
+
'--log-file=/etc/passwd',
|
|
55
|
+
'--load-extension=/tmp/ext',
|
|
56
|
+
];
|
|
57
|
+
assert.deepEqual(filterCloudLaunchArguments(args).allowed, []);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('single dash and upper case spellings are caught too', () => {
|
|
61
|
+
const args = ['-utility-cmd-prefix=/usr/bin/python3', '--Renderer-Cmd-Prefix=/bin/sh', '-PROXY-SERVER=x'];
|
|
62
|
+
assert.deepEqual(filterCloudLaunchArguments(args).allowed, []);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('a bare -- is dropped: it would turn the SDK switches after it into URLs', () => {
|
|
66
|
+
assert.deepEqual(filterCloudLaunchArguments(['--', '--restore-last-session']), {
|
|
67
|
+
allowed: ['--restore-last-session'],
|
|
68
|
+
blocked: ['--'],
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('ordinary launch arguments pass through unchanged and in order', () => {
|
|
73
|
+
const args = [
|
|
74
|
+
'--lang=de-DE',
|
|
75
|
+
'--start-maximized',
|
|
76
|
+
'--window-size=1280,800',
|
|
77
|
+
'--disable-features=Translate',
|
|
78
|
+
'--enable-features=WebGPU',
|
|
79
|
+
'--force-device-scale-factor=1.25',
|
|
80
|
+
'--user-agent=Mozilla/5.0 test',
|
|
81
|
+
'--disable-web-security',
|
|
82
|
+
'https://example.com/start',
|
|
83
|
+
];
|
|
84
|
+
assert.deepEqual(filterCloudLaunchArguments(args), { allowed: args, blocked: [] });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('switch names are read without the value', () => {
|
|
88
|
+
assert.equal(launchSwitchName('--utility-cmd-prefix=/usr/bin/python3'), 'utility-cmd-prefix');
|
|
89
|
+
assert.equal(launchSwitchName('-No-Proxy-Server'), 'no-proxy-server');
|
|
90
|
+
assert.equal(launchSwitchName('https://example.com'), null);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('log description hides proxy credentials but keeps what was run', () => {
|
|
94
|
+
assert.equal(describeBlockedArgument('--proxy-server=http://user:pass@1.2.3.4:8080'), '--proxy-server=<redacted>');
|
|
95
|
+
assert.equal(describeBlockedArgument('--utility-cmd-prefix=/usr/bin/python3'), '--utility-cmd-prefix=/usr/bin/python3');
|
|
96
|
+
});
|