gologin-commonjs 2.1.1
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/babel.config.json +17 -0
- package/dist/README.md +163 -0
- package/dist/example.js +35 -0
- package/dist/examples/example-amazon-cloud-browser.js +52 -0
- package/dist/examples/example-amazon-headless.js +56 -0
- package/dist/examples/example-amazon.js +53 -0
- package/dist/examples/example-create-custom-profile.js +42 -0
- package/dist/examples/example-create-profile.js +43 -0
- package/dist/examples/example-custom-args.js +34 -0
- package/dist/examples/example-fast-profile-settings.js +59 -0
- package/dist/examples/example-gmail.js +82 -0
- package/dist/examples/example-iphey.js +19 -0
- package/dist/examples/example-local-profile.js +28 -0
- package/dist/examples/example-login-walmart.js +38 -0
- package/dist/examples/example-startremote.js +29 -0
- package/dist/examples/example-stopremote.js +22 -0
- package/dist/examples/example-timezone.js +51 -0
- package/dist/fonts.js +3339 -0
- package/dist/fonts_config +104 -0
- package/dist/gologin-browser-ext.zip +0 -0
- package/dist/gologin_zeroprofile.b64 +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/profile_export_example.csv +2 -0
- package/dist/run.sh +1 -0
- package/dist/src/bookmarks/utils.js +23 -0
- package/dist/src/browser/browser-api.js +106 -0
- package/dist/src/browser/browser-checker.js +336 -0
- package/dist/src/browser/browser-user-data-manager.js +306 -0
- package/dist/src/cookies/cookies-manager.js +164 -0
- package/dist/src/extensions/extensions-extractor.js +50 -0
- package/dist/src/extensions/extensions-manager.js +301 -0
- package/dist/src/extensions/user-extensions-manager.js +246 -0
- package/dist/src/gologin-api.js +103 -0
- package/dist/src/gologin.js +1319 -0
- package/dist/src/profile/profile-archiver.js +68 -0
- package/dist/src/profile/profile-directories-to-remove.js +71 -0
- package/dist/src/utils/browser.js +59 -0
- package/dist/src/utils/common.js +60 -0
- package/dist/src/utils/constants.js +7 -0
- package/dist/src/utils/utils.js +53 -0
- package/dist/test.html +1 -0
- package/dist/zero_profile.zip +0 -0
- package/gologin/.eslintrc.json +290 -0
- package/gologin/.sentry-native/a65389b2-9a7d-41ed-7de5-95c4570f0d3d.run.lock +0 -0
- package/gologin/README.md +163 -0
- package/gologin/example.js +36 -0
- package/gologin/examples/example-amazon-cloud-browser.js +44 -0
- package/gologin/examples/example-amazon-headless.js +50 -0
- package/gologin/examples/example-amazon.js +47 -0
- package/gologin/examples/example-create-custom-profile.js +39 -0
- package/gologin/examples/example-create-profile.js +40 -0
- package/gologin/examples/example-custom-args.js +34 -0
- package/gologin/examples/example-fast-profile-settings.js +69 -0
- package/gologin/examples/example-gmail.js +67 -0
- package/gologin/examples/example-iphey.js +17 -0
- package/gologin/examples/example-local-profile.js +26 -0
- package/gologin/examples/example-login-walmart.js +35 -0
- package/gologin/examples/example-startremote.js +25 -0
- package/gologin/examples/example-stopremote.js +20 -0
- package/gologin/examples/example-timezone.js +44 -0
- package/gologin/fonts.js +3339 -0
- package/gologin/fonts_config +104 -0
- package/gologin/gologin-browser-ext.zip +0 -0
- package/gologin/gologin_zeroprofile.b64 +1 -0
- package/gologin/index.d.ts +61 -0
- package/gologin/package.json +49 -0
- package/gologin/profile_export_example.csv +2 -0
- package/gologin/run.sh +1 -0
- package/gologin/src/bookmarks/utils.js +16 -0
- package/gologin/src/browser/browser-api.js +95 -0
- package/gologin/src/browser/browser-checker.js +392 -0
- package/gologin/src/browser/browser-user-data-manager.js +335 -0
- package/gologin/src/cookies/cookies-manager.js +189 -0
- package/gologin/src/extensions/extensions-extractor.js +56 -0
- package/gologin/src/extensions/extensions-manager.js +384 -0
- package/gologin/src/extensions/user-extensions-manager.js +295 -0
- package/gologin/src/gologin-api.js +110 -0
- package/gologin/src/gologin.js +1553 -0
- package/gologin/src/profile/profile-archiver.js +86 -0
- package/gologin/src/profile/profile-directories-to-remove.js +75 -0
- package/gologin/src/utils/browser.js +62 -0
- package/gologin/src/utils/common.js +76 -0
- package/gologin/src/utils/constants.js +1 -0
- package/gologin/src/utils/utils.js +49 -0
- package/gologin/test.html +1 -0
- package/gologin/zero_profile.zip +0 -0
- package/package.json +46 -0
- package/tes.js +35 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.unixToLDAP = exports.loadCookiesFromFile = exports.ldapToUnix = exports.getDB = exports.getCookiesFilePath = exports.getChunckedInsertValues = exports.chunk = exports.buildCookieURL = void 0;
|
|
7
|
+
var _sqlite = require("sqlite");
|
|
8
|
+
var _sqlite2 = _interopRequireDefault(require("sqlite3"));
|
|
9
|
+
var _fs = require("fs");
|
|
10
|
+
var _path = require("path");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
const {
|
|
13
|
+
access
|
|
14
|
+
} = _fs.promises;
|
|
15
|
+
const {
|
|
16
|
+
Database,
|
|
17
|
+
OPEN_READONLY
|
|
18
|
+
} = _sqlite2.default;
|
|
19
|
+
const MAX_SQLITE_VARIABLES = 76;
|
|
20
|
+
const SAME_SITE = {
|
|
21
|
+
'-1': 'unspecified',
|
|
22
|
+
0: 'no_restriction',
|
|
23
|
+
1: 'lax',
|
|
24
|
+
2: 'strict'
|
|
25
|
+
};
|
|
26
|
+
const getDB = (filePath, readOnly = true) => {
|
|
27
|
+
const connectionOpts = {
|
|
28
|
+
filename: filePath,
|
|
29
|
+
driver: Database
|
|
30
|
+
};
|
|
31
|
+
if (readOnly) {
|
|
32
|
+
connectionOpts.mode = OPEN_READONLY;
|
|
33
|
+
}
|
|
34
|
+
return (0, _sqlite.open)(connectionOpts);
|
|
35
|
+
};
|
|
36
|
+
exports.getDB = getDB;
|
|
37
|
+
const getChunckedInsertValues = cookiesArr => {
|
|
38
|
+
const todayUnix = Math.floor(new Date().getTime() / 1000.0);
|
|
39
|
+
const chunckedCookiesArr = chunk(cookiesArr, MAX_SQLITE_VARIABLES);
|
|
40
|
+
return chunckedCookiesArr.map(cookies => {
|
|
41
|
+
const queryPlaceholders = cookies.map(() => '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)').join(', ');
|
|
42
|
+
const query = `insert or replace into cookies (creation_utc, host_key, top_frame_site_key, name, value, encrypted_value, path, expires_utc, is_secure, is_httponly, last_access_utc, has_expires, is_persistent, priority, samesite, source_scheme, source_port, is_same_party, last_update_utc) values ${queryPlaceholders}`;
|
|
43
|
+
const queryParams = cookies.flatMap(cookie => {
|
|
44
|
+
const creationDate = cookie.creationDate ? cookie.creationDate : unixToLDAP(todayUnix);
|
|
45
|
+
let expirationDate = cookie.session ? 0 : unixToLDAP(cookie.expirationDate);
|
|
46
|
+
const encryptedValue = cookie.value;
|
|
47
|
+
const samesite = Object.keys(SAME_SITE).find(key => SAME_SITE[key] === (cookie.sameSite || '-1'));
|
|
48
|
+
const isSecure = cookie.name.startsWith('__Host-') || cookie.name.startsWith('__Secure-') ? 1 : Number(cookie.secure);
|
|
49
|
+
const sourceScheme = isSecure === 1 ? 2 : 1;
|
|
50
|
+
const sourcePort = isSecure === 1 ? 443 : 80;
|
|
51
|
+
// eslint-disable-next-line no-undefined
|
|
52
|
+
let isPersistent = [undefined, null].includes(cookie.session) ? Number(expirationDate !== 0) : Number(!cookie.session);
|
|
53
|
+
if (/^(\.)?mail.google.com$/.test(cookie.domain) && cookie.name === 'COMPASS') {
|
|
54
|
+
expirationDate = 0;
|
|
55
|
+
isPersistent = 0;
|
|
56
|
+
}
|
|
57
|
+
return [creationDate, cookie.domain, '',
|
|
58
|
+
// top_frame_site_key
|
|
59
|
+
cookie.name, '',
|
|
60
|
+
// value
|
|
61
|
+
encryptedValue, cookie.path, expirationDate, isSecure, Number(cookie.httpOnly), 0,
|
|
62
|
+
// last_access_utc
|
|
63
|
+
expirationDate === 0 ? 0 : 1,
|
|
64
|
+
// has_expires
|
|
65
|
+
isPersistent, 1,
|
|
66
|
+
// default priority value (https://github.com/chromium/chromium/blob/main/net/cookies/cookie_constants.h)
|
|
67
|
+
samesite, sourceScheme, sourcePort, 0,
|
|
68
|
+
// is_same_party
|
|
69
|
+
0 // last_update_utc
|
|
70
|
+
];
|
|
71
|
+
});
|
|
72
|
+
return [query, queryParams];
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
exports.getChunckedInsertValues = getChunckedInsertValues;
|
|
76
|
+
const loadCookiesFromFile = async filePath => {
|
|
77
|
+
let db;
|
|
78
|
+
const cookies = [];
|
|
79
|
+
try {
|
|
80
|
+
db = await getDB(filePath);
|
|
81
|
+
const cookiesRows = await db.all('select * from cookies');
|
|
82
|
+
for (const row of cookiesRows) {
|
|
83
|
+
const {
|
|
84
|
+
host_key,
|
|
85
|
+
name,
|
|
86
|
+
encrypted_value,
|
|
87
|
+
path,
|
|
88
|
+
is_secure,
|
|
89
|
+
is_httponly,
|
|
90
|
+
expires_utc,
|
|
91
|
+
is_persistent,
|
|
92
|
+
samesite,
|
|
93
|
+
creation_utc
|
|
94
|
+
} = row;
|
|
95
|
+
cookies.push({
|
|
96
|
+
url: buildCookieURL(host_key, is_secure, path),
|
|
97
|
+
domain: host_key,
|
|
98
|
+
name,
|
|
99
|
+
value: encrypted_value,
|
|
100
|
+
path,
|
|
101
|
+
sameSite: SAME_SITE[samesite],
|
|
102
|
+
secure: Boolean(is_secure),
|
|
103
|
+
httpOnly: Boolean(is_httponly),
|
|
104
|
+
hostOnly: !host_key.startsWith('.'),
|
|
105
|
+
session: !is_persistent,
|
|
106
|
+
expirationDate: ldapToUnix(expires_utc),
|
|
107
|
+
creationDate: ldapToUnix(creation_utc)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.log(error);
|
|
112
|
+
} finally {
|
|
113
|
+
db && (await db.close());
|
|
114
|
+
}
|
|
115
|
+
return cookies;
|
|
116
|
+
};
|
|
117
|
+
exports.loadCookiesFromFile = loadCookiesFromFile;
|
|
118
|
+
const unixToLDAP = unixtime => {
|
|
119
|
+
if (unixtime === 0) {
|
|
120
|
+
return unixtime;
|
|
121
|
+
}
|
|
122
|
+
const win32filetime = new Date(Date.UTC(1601, 0, 1)).getTime() / 1000;
|
|
123
|
+
const sum = unixtime - win32filetime;
|
|
124
|
+
return sum * 1000000;
|
|
125
|
+
};
|
|
126
|
+
exports.unixToLDAP = unixToLDAP;
|
|
127
|
+
const ldapToUnix = ldap => {
|
|
128
|
+
const ldapLength = ldap.toString().length;
|
|
129
|
+
if (ldap === 0 || ldapLength > 18) {
|
|
130
|
+
return ldap;
|
|
131
|
+
}
|
|
132
|
+
let _ldap = ldap;
|
|
133
|
+
if (ldapLength < 18) {
|
|
134
|
+
_ldap = Number(_ldap + '0'.repeat(18 - ldapLength));
|
|
135
|
+
}
|
|
136
|
+
const win32filetime = new Date(Date.UTC(1601, 0, 1)).getTime();
|
|
137
|
+
return (_ldap / 10000 + win32filetime) / 1000;
|
|
138
|
+
};
|
|
139
|
+
exports.ldapToUnix = ldapToUnix;
|
|
140
|
+
const buildCookieURL = (domain, secure, path) => {
|
|
141
|
+
let domainWithoutDot = domain;
|
|
142
|
+
if (domain.startsWith('.')) {
|
|
143
|
+
domainWithoutDot = domain.substr(1);
|
|
144
|
+
}
|
|
145
|
+
return 'http' + (secure ? 's' : '') + '://' + domainWithoutDot + path;
|
|
146
|
+
};
|
|
147
|
+
exports.buildCookieURL = buildCookieURL;
|
|
148
|
+
const chunk = (arr, chunkSize = 1, cache = []) => {
|
|
149
|
+
const tmp = [...arr];
|
|
150
|
+
if (chunkSize <= 0) {
|
|
151
|
+
return cache;
|
|
152
|
+
}
|
|
153
|
+
while (tmp.length) {
|
|
154
|
+
cache.push(tmp.splice(0, chunkSize));
|
|
155
|
+
}
|
|
156
|
+
return cache;
|
|
157
|
+
};
|
|
158
|
+
exports.chunk = chunk;
|
|
159
|
+
const getCookiesFilePath = async (profileId, tmpdir) => {
|
|
160
|
+
const baseCookiesFilePath = (0, _path.join)(tmpdir, `gologin_profile_${profileId}`, 'Default', 'Cookies');
|
|
161
|
+
const bypassCookiesFilePath = (0, _path.join)(tmpdir, `gologin_profile_${profileId}`, 'Default', 'Network', 'Cookies');
|
|
162
|
+
return access(baseCookiesFilePath).then(() => baseCookiesFilePath).catch(() => access(bypassCookiesFilePath).then(() => bypassCookiesFilePath).catch(() => baseCookiesFilePath));
|
|
163
|
+
};
|
|
164
|
+
exports.getCookiesFilePath = getCookiesFilePath;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.extractExtension = exports.deleteExtensionArchive = void 0;
|
|
7
|
+
var _decompress = _interopRequireDefault(require("decompress"));
|
|
8
|
+
var _decompressUnzip = _interopRequireDefault(require("decompress-unzip"));
|
|
9
|
+
var _fs = require("fs");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
const {
|
|
12
|
+
access,
|
|
13
|
+
unlink
|
|
14
|
+
} = _fs.promises;
|
|
15
|
+
const extractExtension = (source, dest) => {
|
|
16
|
+
if (!(source && dest)) {
|
|
17
|
+
throw new Error('Missing parameter');
|
|
18
|
+
}
|
|
19
|
+
return access(source).then(() => withRetry({
|
|
20
|
+
fn() {
|
|
21
|
+
return (0, _decompress.default)(source, dest, {
|
|
22
|
+
plugins: [(0, _decompressUnzip.default)()],
|
|
23
|
+
filter: file => !file.path.endsWith('/')
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}));
|
|
27
|
+
};
|
|
28
|
+
exports.extractExtension = extractExtension;
|
|
29
|
+
const deleteExtensionArchive = dest => {
|
|
30
|
+
if (!dest) {
|
|
31
|
+
throw new Error('Missing parameter');
|
|
32
|
+
}
|
|
33
|
+
return access(dest).then(() => unlink(dest), () => Promise.resolve());
|
|
34
|
+
};
|
|
35
|
+
exports.deleteExtensionArchive = deleteExtensionArchive;
|
|
36
|
+
const withRetry = optionsOrUndefined => {
|
|
37
|
+
const opts = optionsOrUndefined || {};
|
|
38
|
+
const callCounter = opts.callCounter || 1;
|
|
39
|
+
const fnToProducePromise = opts.fn;
|
|
40
|
+
const callLimit = opts.limit || 5;
|
|
41
|
+
delete opts.callCounter;
|
|
42
|
+
return fnToProducePromise(opts).catch(err => {
|
|
43
|
+
console.error(err);
|
|
44
|
+
if (callCounter >= callLimit) {
|
|
45
|
+
return Promise.reject(err);
|
|
46
|
+
}
|
|
47
|
+
opts.callCounter = callCounter + 1;
|
|
48
|
+
return new Promise(resolve => process.nextTick(resolve)).then(() => withRetry(opts));
|
|
49
|
+
});
|
|
50
|
+
};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.ExtensionsManager = void 0;
|
|
7
|
+
var _fs = require("fs");
|
|
8
|
+
var _path = require("path");
|
|
9
|
+
var _requestretry = _interopRequireDefault(require("requestretry"));
|
|
10
|
+
var _common = require("../utils/common.js");
|
|
11
|
+
var _userExtensionsManager = _interopRequireDefault(require("./user-extensions-manager.js"));
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
const {
|
|
14
|
+
mkdir,
|
|
15
|
+
readdir,
|
|
16
|
+
rmdir,
|
|
17
|
+
unlink
|
|
18
|
+
} = _fs.promises;
|
|
19
|
+
const EXTENSION_URL = 'https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D{ext_id}%26uc&prodversion=97.0.4692.71';
|
|
20
|
+
class ExtensionsManager extends _userExtensionsManager.default {
|
|
21
|
+
#existedChromeExtensions = [];
|
|
22
|
+
#inited = false;
|
|
23
|
+
#useLocalExtStorage = false;
|
|
24
|
+
#useCookiesExt = false;
|
|
25
|
+
#deleteProfileExtFolders = false;
|
|
26
|
+
#extensionsUpdating = true;
|
|
27
|
+
constructor() {
|
|
28
|
+
super();
|
|
29
|
+
if (!ExtensionsManager.instance) {
|
|
30
|
+
ExtensionsManager.instance = this;
|
|
31
|
+
}
|
|
32
|
+
return ExtensionsManager.instance;
|
|
33
|
+
}
|
|
34
|
+
async init() {
|
|
35
|
+
if (this.#inited) {
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
const promises = [mkdir(_common.CHROME_EXTENSIONS_PATH, {
|
|
39
|
+
recursive: true
|
|
40
|
+
}).then(() => readdir(_common.CHROME_EXTENSIONS_PATH)).then(filesList => {
|
|
41
|
+
this.#existedChromeExtensions = filesList.filter(extPath => !extPath.includes('.zip'));
|
|
42
|
+
return filesList.map(fileName => fileName.includes('.zip') ? unlink((0, _path.join)(_common.CHROME_EXTENSIONS_PATH, fileName)) : Promise.resolve());
|
|
43
|
+
}).then(promisesToDelete => Promise.all(promisesToDelete)).catch(e => console.log('ExtensionsManager init error:', e)), mkdir(_common.USER_EXTENSIONS_PATH, {
|
|
44
|
+
recursive: true
|
|
45
|
+
}).then(() => readdir(_common.USER_EXTENSIONS_PATH)).then(filesList => {
|
|
46
|
+
this.existedUserExtensions = filesList.filter(extPath => !extPath.includes('.zip'));
|
|
47
|
+
return filesList.map(fileName => fileName.includes('.zip') ? unlink((0, _path.join)(_common.USER_EXTENSIONS_PATH, fileName)) : Promise.resolve());
|
|
48
|
+
}).then(promisesToDelete => Promise.all(promisesToDelete)).catch(e => console.log('error creating user extensions folder:', e))];
|
|
49
|
+
return Promise.all(promises).then(() => this.#inited = true);
|
|
50
|
+
}
|
|
51
|
+
get isInited() {
|
|
52
|
+
return this.#inited;
|
|
53
|
+
}
|
|
54
|
+
get useLocalExtStorage() {
|
|
55
|
+
return this.#useLocalExtStorage;
|
|
56
|
+
}
|
|
57
|
+
get deleteProfileExtFolders() {
|
|
58
|
+
return this.#deleteProfileExtFolders;
|
|
59
|
+
}
|
|
60
|
+
get useCookiesExt() {
|
|
61
|
+
return this.#useCookiesExt;
|
|
62
|
+
}
|
|
63
|
+
get existedChromeExtensionsList() {
|
|
64
|
+
return this.#existedChromeExtensions;
|
|
65
|
+
}
|
|
66
|
+
async checkChromeExtensions(profileExtensions = []) {
|
|
67
|
+
if (!(Array.isArray(profileExtensions) && profileExtensions.length)) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const extensionsToDownload = this.#getExtensionsToDownload(profileExtensions);
|
|
71
|
+
const downloadedArchives = await this.downloadChromeExtensions(extensionsToDownload);
|
|
72
|
+
const filteredArchives = downloadedArchives.filter(Boolean);
|
|
73
|
+
if (filteredArchives.length) {
|
|
74
|
+
const [downloadedFolders] = filteredArchives.map(archivePath => archivePath.split(_path.sep).reverse());
|
|
75
|
+
this.#existedChromeExtensions = [...this.#existedChromeExtensions, ...downloadedFolders];
|
|
76
|
+
const promises = (0, _common.composeExtractionPromises)(filteredArchives);
|
|
77
|
+
await Promise.all(promises);
|
|
78
|
+
}
|
|
79
|
+
return this.getExtensionsStrToIncludeAsOrbitaParam(profileExtensions);
|
|
80
|
+
}
|
|
81
|
+
#getExtensionsToDownload(profileExtensions) {
|
|
82
|
+
const existedExtensionsFolders = [...this.#existedChromeExtensions, ...this.existedUserExtensions];
|
|
83
|
+
const existedOriginalIds = existedExtensionsFolders.map(val => {
|
|
84
|
+
const [originalId] = val.split('@');
|
|
85
|
+
return originalId;
|
|
86
|
+
});
|
|
87
|
+
return profileExtensions.reduce((res, val) => {
|
|
88
|
+
const [originalId] = val.split('@');
|
|
89
|
+
const extensionExists = existedOriginalIds.includes(originalId);
|
|
90
|
+
if (!extensionExists) {
|
|
91
|
+
res.push(val);
|
|
92
|
+
}
|
|
93
|
+
return res;
|
|
94
|
+
}, []);
|
|
95
|
+
}
|
|
96
|
+
async downloadChromeExtensions(idsToDownload = []) {
|
|
97
|
+
if (!(Array.isArray(idsToDownload) && idsToDownload.length)) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const promises = idsToDownload.map(async id => {
|
|
101
|
+
const [originalId] = id.split('@');
|
|
102
|
+
const extUrl = EXTENSION_URL.replace('{ext_id}', originalId);
|
|
103
|
+
const uploadedProfileMetadata = await getExtMetadata(extUrl);
|
|
104
|
+
const reqPath = uploadedProfileMetadata.req.path;
|
|
105
|
+
const extVer = getExtVersion(reqPath);
|
|
106
|
+
const buffer = await new Promise(res => {
|
|
107
|
+
const chunks = [];
|
|
108
|
+
_requestretry.default.get(extUrl, {
|
|
109
|
+
maxAttempts: 3,
|
|
110
|
+
retryDelay: 1000,
|
|
111
|
+
timeout: 8 * 1000,
|
|
112
|
+
fullResponse: false
|
|
113
|
+
}).on('data', data => chunks.push(data)).on('end', () => res(Buffer.concat(chunks)));
|
|
114
|
+
});
|
|
115
|
+
let zipExt;
|
|
116
|
+
try {
|
|
117
|
+
zipExt = crxToZip(buffer);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
console.log(e);
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
const archiveZipPath = (0, _path.join)(_common.CHROME_EXTENSIONS_PATH, originalId + '@' + extVer + '.zip');
|
|
123
|
+
const archiveZip = (0, _fs.createWriteStream)(archiveZipPath);
|
|
124
|
+
archiveZip.write(zipExt);
|
|
125
|
+
archiveZip.close();
|
|
126
|
+
return new Promise(r => archiveZip.on('close', () => r(archiveZipPath)));
|
|
127
|
+
});
|
|
128
|
+
return Promise.all(promises);
|
|
129
|
+
}
|
|
130
|
+
async getExtensionsPolicies() {
|
|
131
|
+
const globalExtConfig = await _requestretry.default.get(`${this.apiBaseUrl}/gologin-settings/chrome_ext_policies`, {
|
|
132
|
+
headers: {
|
|
133
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
134
|
+
'user-agent': this.userAgent,
|
|
135
|
+
'x-two-factor-token': this.twoFaKey || ''
|
|
136
|
+
},
|
|
137
|
+
json: true,
|
|
138
|
+
maxAttempts: 2,
|
|
139
|
+
retryDelay: 1000,
|
|
140
|
+
timeout: 10 * 1000,
|
|
141
|
+
fullResponse: false
|
|
142
|
+
});
|
|
143
|
+
const chromeExtPolicies = globalExtConfig?.chromeExtPolicies || {};
|
|
144
|
+
const {
|
|
145
|
+
useLocalExtStorage = false,
|
|
146
|
+
deleteProfileExtFolders = false,
|
|
147
|
+
useCookiesExt = true
|
|
148
|
+
} = chromeExtPolicies;
|
|
149
|
+
this.#useLocalExtStorage = useLocalExtStorage;
|
|
150
|
+
this.#deleteProfileExtFolders = deleteProfileExtFolders;
|
|
151
|
+
this.#useCookiesExt = useCookiesExt;
|
|
152
|
+
}
|
|
153
|
+
async updateExtensions() {
|
|
154
|
+
const fileList = await readdir(_common.CHROME_EXTENSIONS_PATH).catch(() => []);
|
|
155
|
+
if (!fileList.length) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const oldFolders = [];
|
|
159
|
+
const versionCheckPromises = fileList.map(async extension => {
|
|
160
|
+
if (!extension.includes('@') || extension.includes('.zip')) {
|
|
161
|
+
return '';
|
|
162
|
+
}
|
|
163
|
+
const [originalId, currentVersion] = extension.split('@');
|
|
164
|
+
const extUrl = EXTENSION_URL.replace('{ext_id}', originalId);
|
|
165
|
+
const uploadedProfileMetadata = await getExtMetadata(extUrl);
|
|
166
|
+
const reqPath = uploadedProfileMetadata.req.path;
|
|
167
|
+
const availableVersion = getExtVersion(reqPath);
|
|
168
|
+
if (currentVersion === availableVersion) {
|
|
169
|
+
return '';
|
|
170
|
+
}
|
|
171
|
+
oldFolders.push((0, _path.join)(_common.CHROME_EXTENSIONS_PATH, extension));
|
|
172
|
+
return originalId;
|
|
173
|
+
});
|
|
174
|
+
const extensionsNames = (await Promise.all(versionCheckPromises)).filter(Boolean);
|
|
175
|
+
const archivesPaths = (await this.downloadChromeExtensions(extensionsNames)).filter(Boolean);
|
|
176
|
+
const extractionPromises = (0, _common.composeExtractionPromises)(archivesPaths);
|
|
177
|
+
await Promise.all(extractionPromises);
|
|
178
|
+
const removeFoldersPromises = oldFolders.map(folder => rmdir(folder, {
|
|
179
|
+
recursive: true,
|
|
180
|
+
maxRetries: 3
|
|
181
|
+
}).catch(() => {}));
|
|
182
|
+
await Promise.all(removeFoldersPromises).then(() => this.#extensionsUpdating = false);
|
|
183
|
+
}
|
|
184
|
+
async checkLocalExtensions() {
|
|
185
|
+
if (this.#extensionsUpdating || !this.accessToken) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const fileList = await readdir(_common.CHROME_EXTENSIONS_PATH).catch(() => []);
|
|
189
|
+
if (!fileList.length) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const extensionsIds = fileList.filter(folderName => folderName.includes('@') && !folderName.includes('.zip')).map(folderName => {
|
|
193
|
+
const [name] = folderName.split('@');
|
|
194
|
+
return name;
|
|
195
|
+
});
|
|
196
|
+
if (!extensionsIds.length) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
this.insertExtensionsToDb(extensionsIds);
|
|
200
|
+
}
|
|
201
|
+
async insertExtensionsToDb(extensionsIds, pathToExtensions = _common.CHROME_EXTENSIONS_PATH) {
|
|
202
|
+
if (!extensionsIds?.length) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const checkResponse = await (0, _requestretry.default)(`${this.apiBaseUrl}/extensions/check`, {
|
|
206
|
+
method: 'POST',
|
|
207
|
+
headers: {
|
|
208
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
209
|
+
'user-agent': this.userAgent,
|
|
210
|
+
'x-two-factor-token': this.twoFaKey || ''
|
|
211
|
+
},
|
|
212
|
+
body: {
|
|
213
|
+
extensionsIds
|
|
214
|
+
},
|
|
215
|
+
json: true
|
|
216
|
+
});
|
|
217
|
+
const {
|
|
218
|
+
extensionsToAdd = []
|
|
219
|
+
} = checkResponse.body;
|
|
220
|
+
if (!extensionsToAdd.length) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const extensionsToUpdate = await this.getExtensionsNameAndImage(extensionsToAdd, pathToExtensions);
|
|
224
|
+
(0, _requestretry.default)(`${this.apiBaseUrl}/extensions/create`, {
|
|
225
|
+
method: 'POST',
|
|
226
|
+
headers: {
|
|
227
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
228
|
+
'user-agent': this.userAgent,
|
|
229
|
+
'x-two-factor-token': this.twoFaKey || ''
|
|
230
|
+
},
|
|
231
|
+
body: {
|
|
232
|
+
extensionsInfo: extensionsToUpdate
|
|
233
|
+
},
|
|
234
|
+
json: true
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
getExtensionsToInstall(extensionsFromPref, extensionsFromDB) {
|
|
238
|
+
if (!extensionsFromPref) {
|
|
239
|
+
return [];
|
|
240
|
+
}
|
|
241
|
+
const objectEntries = Object.entries(extensionsFromPref);
|
|
242
|
+
const extensionsInPref = objectEntries?.map(([_, settings]) => {
|
|
243
|
+
const [extFolderName] = settings.path.split(_path.sep).reverse();
|
|
244
|
+
const [originalId] = extFolderName.split('@');
|
|
245
|
+
return originalId;
|
|
246
|
+
}) || [];
|
|
247
|
+
return extensionsFromDB.reduce((acc, extension) => {
|
|
248
|
+
const [extFolderName] = extension.split(_path.sep).reverse();
|
|
249
|
+
const [originalId] = extFolderName.split('@');
|
|
250
|
+
if (!extensionsInPref.includes(originalId)) {
|
|
251
|
+
acc.push(extension);
|
|
252
|
+
}
|
|
253
|
+
return acc;
|
|
254
|
+
}, []);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
exports.ExtensionsManager = ExtensionsManager;
|
|
258
|
+
const crxToZip = buf => {
|
|
259
|
+
if (buf[0] === 80 && buf[1] === 75 && buf[2] === 3 && buf[3] === 4) {
|
|
260
|
+
return buf;
|
|
261
|
+
}
|
|
262
|
+
if (!(buf[0] === 67 || buf[1] === 114 || buf[2] === 50 || buf[3] === 52)) {
|
|
263
|
+
throw new Error('Invalid header: Does not start with Cr24');
|
|
264
|
+
}
|
|
265
|
+
const isV3 = buf[4] === 3;
|
|
266
|
+
const isV2 = buf[4] === 2;
|
|
267
|
+
if (!(isV2 || isV3) || buf[5] || buf[6] || buf[7]) {
|
|
268
|
+
throw new Error('Unexpected crx format version number.');
|
|
269
|
+
}
|
|
270
|
+
if (isV2) {
|
|
271
|
+
const publicKeyLength = calcLength(buf[8], buf[9], buf[10], buf[11]);
|
|
272
|
+
const signatureLength = calcLength(buf[12], buf[13], buf[14], buf[15]);
|
|
273
|
+
const zipStartOffset = 16 + publicKeyLength + signatureLength;
|
|
274
|
+
return buf.slice(zipStartOffset, buf.length);
|
|
275
|
+
}
|
|
276
|
+
const headerSize = calcLength(buf[8], buf[9], buf[10], buf[11]);
|
|
277
|
+
const zipStartOffset = 12 + headerSize;
|
|
278
|
+
return buf.slice(zipStartOffset, buf.length);
|
|
279
|
+
};
|
|
280
|
+
const calcLength = (a, b, c, d) => {
|
|
281
|
+
let length = 0;
|
|
282
|
+
length += a << 0;
|
|
283
|
+
length += b << 8;
|
|
284
|
+
length += c << 16;
|
|
285
|
+
length += d << 24 >>> 0;
|
|
286
|
+
return length;
|
|
287
|
+
};
|
|
288
|
+
const getExtMetadata = extUrl => _requestretry.default.head(extUrl, {
|
|
289
|
+
maxAttempts: 3,
|
|
290
|
+
retryDelay: 2000,
|
|
291
|
+
timeout: 2 * 1000,
|
|
292
|
+
fullResponse: true
|
|
293
|
+
});
|
|
294
|
+
const getExtVersion = metadata => {
|
|
295
|
+
const [extFullName = ''] = metadata.split('/').reverse();
|
|
296
|
+
const [extName = ''] = extFullName.split('.');
|
|
297
|
+
const splitExtName = extName.split('_');
|
|
298
|
+
splitExtName.shift();
|
|
299
|
+
return splitExtName.join('_');
|
|
300
|
+
};
|
|
301
|
+
var _default = exports.default = ExtensionsManager;
|