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,1319 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.GoLogin = void 0;
|
|
7
|
+
Object.defineProperty(exports, "GologinApi", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return _gologinApi.GologinApi;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
exports.default = void 0;
|
|
14
|
+
Object.defineProperty(exports, "exitAll", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () {
|
|
17
|
+
return _gologinApi.exitAll;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
var _child_process = require("child_process");
|
|
21
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
22
|
+
var _decompress = _interopRequireDefault(require("decompress"));
|
|
23
|
+
var _decompressUnzip = _interopRequireDefault(require("decompress-unzip"));
|
|
24
|
+
var _fs = require("fs");
|
|
25
|
+
var _https = require("https");
|
|
26
|
+
var _os = require("os");
|
|
27
|
+
var _path = require("path");
|
|
28
|
+
var _requestretry = _interopRequireDefault(require("requestretry"));
|
|
29
|
+
var _rimraf = _interopRequireDefault(require("rimraf"));
|
|
30
|
+
var _socksProxyAgent = require("socks-proxy-agent");
|
|
31
|
+
var _fonts = require("../fonts.js");
|
|
32
|
+
var _utils = require("./bookmarks/utils.js");
|
|
33
|
+
var _browserApi = require("./browser/browser-api.js");
|
|
34
|
+
var _browserChecker = _interopRequireDefault(require("./browser/browser-checker.js"));
|
|
35
|
+
var _browserUserDataManager = require("./browser/browser-user-data-manager.js");
|
|
36
|
+
var _cookiesManager = require("./cookies/cookies-manager.js");
|
|
37
|
+
var _extensionsManager = _interopRequireDefault(require("./extensions/extensions-manager.js"));
|
|
38
|
+
var _profileArchiver = require("./profile/profile-archiver.js");
|
|
39
|
+
var _browser = require("./utils/browser.js");
|
|
40
|
+
var _common = require("./utils/common.js");
|
|
41
|
+
var _constants = require("./utils/constants.js");
|
|
42
|
+
var _utils2 = require("./utils/utils.js");
|
|
43
|
+
var _gologinApi = require("./gologin-api.js");
|
|
44
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
45
|
+
const {
|
|
46
|
+
access,
|
|
47
|
+
unlink,
|
|
48
|
+
writeFile,
|
|
49
|
+
readFile
|
|
50
|
+
} = _fs.promises;
|
|
51
|
+
const SEPARATOR = _path.sep;
|
|
52
|
+
const OS_PLATFORM = process.platform;
|
|
53
|
+
const TIMEZONE_URL = 'https://geo.myip.link';
|
|
54
|
+
const PROXY_NONE = 'none';
|
|
55
|
+
const debug = (0, _debug.default)('gologin');
|
|
56
|
+
const delay = time => new Promise(resolve => setTimeout(resolve, time));
|
|
57
|
+
class GoLogin {
|
|
58
|
+
constructor(options = {}) {
|
|
59
|
+
this.browserLang = 'en-US';
|
|
60
|
+
this.is_remote = options.remote || false;
|
|
61
|
+
this.access_token = options.token;
|
|
62
|
+
this.profile_id = options.profile_id;
|
|
63
|
+
this.password = options.password;
|
|
64
|
+
this.extra_params = options.extra_params;
|
|
65
|
+
this.executablePath = options.executablePath;
|
|
66
|
+
this.vnc_port = options.vncPort;
|
|
67
|
+
this.fontsMasking = false;
|
|
68
|
+
this.is_active = false;
|
|
69
|
+
this.is_stopping = false;
|
|
70
|
+
this.differentOs = false;
|
|
71
|
+
this.profileOs = 'lin';
|
|
72
|
+
this.waitWebsocket = options.waitWebsocket ?? true;
|
|
73
|
+
this.isCloudHeadless = options.isCloudHeadless ?? true;
|
|
74
|
+
this.isNewCloudBrowser = options.isNewCloudBrowser ?? true;
|
|
75
|
+
this.tmpdir = (0, _os.tmpdir)();
|
|
76
|
+
this.autoUpdateBrowser = !!options.autoUpdateBrowser;
|
|
77
|
+
this.checkBrowserUpdate = options.checkBrowserUpdate ?? true;
|
|
78
|
+
this.browserChecker = new _browserChecker.default(options.skipOrbitaHashChecking);
|
|
79
|
+
this.uploadCookiesToServer = options.uploadCookiesToServer || false;
|
|
80
|
+
this.writeCookiesFromServer = options.writeCookiesFromServer;
|
|
81
|
+
this.remote_debugging_port = options.remote_debugging_port || 0;
|
|
82
|
+
this.timezone = options.timezone;
|
|
83
|
+
this.extensionPathsToInstall = [];
|
|
84
|
+
this.customArgs = options.args || [];
|
|
85
|
+
this.restoreLastSession = options.restoreLastSession || false;
|
|
86
|
+
this.processSpawned = null;
|
|
87
|
+
this.processKillTimeout = 1 * 1000;
|
|
88
|
+
if (options.tmpdir) {
|
|
89
|
+
this.tmpdir = options.tmpdir;
|
|
90
|
+
if (!(0, _fs.existsSync)(this.tmpdir)) {
|
|
91
|
+
debug('making tmpdir', this.tmpdir);
|
|
92
|
+
(0, _fs.mkdirSync)(this.tmpdir, {
|
|
93
|
+
recursive: true
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
this.profile_zip_path = (0, _path.join)(this.tmpdir, `gologin_${this.profile_id}.zip`);
|
|
98
|
+
this.bookmarksFilePath = (0, _path.join)(this.tmpdir, `gologin_profile_${this.profile_id}`, 'Default', 'Bookmarks');
|
|
99
|
+
debug('INIT GOLOGIN', this.profile_id);
|
|
100
|
+
}
|
|
101
|
+
async checkBrowser() {
|
|
102
|
+
return this.browserChecker.checkBrowser(this.autoUpdateBrowser, this.checkBrowserUpdate);
|
|
103
|
+
}
|
|
104
|
+
async setProfileId(profile_id) {
|
|
105
|
+
this.profile_id = profile_id;
|
|
106
|
+
this.cookiesFilePath = await (0, _cookiesManager.getCookiesFilePath)(profile_id, this.tmpdir);
|
|
107
|
+
this.profile_zip_path = (0, _path.join)(this.tmpdir, `gologin_${this.profile_id}.zip`);
|
|
108
|
+
this.bookmarksFilePath = (0, _path.join)(this.tmpdir, `gologin_profile_${this.profile_id}`, 'Default', 'Bookmarks');
|
|
109
|
+
}
|
|
110
|
+
async getToken(username, password) {
|
|
111
|
+
const data = await _requestretry.default.post(`${_common.API_URL}/user/login`, {
|
|
112
|
+
json: {
|
|
113
|
+
username,
|
|
114
|
+
password
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
if (!Reflect.has(data, 'body.access_token')) {
|
|
118
|
+
throw new Error(`gologin auth failed with status code, ${data.statusCode} DATA ${JSON.stringify(data)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async getNewFingerPrint(os) {
|
|
122
|
+
debug('GETTING FINGERPRINT');
|
|
123
|
+
const fpResponse = await _requestretry.default.get(`${_common.API_URL}/browser/fingerprint?os=${os}`, {
|
|
124
|
+
json: true,
|
|
125
|
+
headers: {
|
|
126
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
127
|
+
'User-Agent': 'gologin-api'
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return fpResponse?.body || {};
|
|
131
|
+
}
|
|
132
|
+
async profiles() {
|
|
133
|
+
const profilesResponse = await _requestretry.default.get(`${_common.API_URL}/browser/v2`, {
|
|
134
|
+
headers: {
|
|
135
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
136
|
+
'User-Agent': 'gologin-api'
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
if (profilesResponse.statusCode !== 200) {
|
|
140
|
+
throw new Error('Gologin /browser response error');
|
|
141
|
+
}
|
|
142
|
+
return JSON.parse(profilesResponse.body);
|
|
143
|
+
}
|
|
144
|
+
async getProfile(profile_id) {
|
|
145
|
+
const id = profile_id || this.profile_id;
|
|
146
|
+
debug('getProfile', this.access_token, id);
|
|
147
|
+
const profileResponse = await _requestretry.default.get(`${_common.API_URL}/browser/${id}`, {
|
|
148
|
+
headers: {
|
|
149
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
150
|
+
'User-Agent': 'gologin-api'
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
debug('profileResponse', profileResponse.statusCode, profileResponse.body);
|
|
154
|
+
const {
|
|
155
|
+
body: errorBody = ''
|
|
156
|
+
} = profileResponse;
|
|
157
|
+
const backendErrorHeader = 'backend@error::';
|
|
158
|
+
if (errorBody.includes(backendErrorHeader)) {
|
|
159
|
+
const errorData = errorBody.replace(backendErrorHeader, '').slice(1, -1);
|
|
160
|
+
throw new Error(errorData);
|
|
161
|
+
}
|
|
162
|
+
if (profileResponse.statusCode === 404) {
|
|
163
|
+
throw new Error(JSON.parse(profileResponse.body).message);
|
|
164
|
+
}
|
|
165
|
+
if (profileResponse.statusCode === 403) {
|
|
166
|
+
throw new Error(JSON.parse(profileResponse.body).message);
|
|
167
|
+
}
|
|
168
|
+
if (profileResponse.statusCode !== 200) {
|
|
169
|
+
throw new Error(`Gologin /browser/${id} response error ${profileResponse.statusCode} INVALID TOKEN OR PROFILE NOT FOUND`);
|
|
170
|
+
}
|
|
171
|
+
if (profileResponse.statusCode === 401) {
|
|
172
|
+
throw new Error('invalid token');
|
|
173
|
+
}
|
|
174
|
+
return JSON.parse(profileResponse.body);
|
|
175
|
+
}
|
|
176
|
+
async emptyProfile() {
|
|
177
|
+
return readFile((0, _path.resolve)(__dirname, 'gologin_zeroprofile.b64')).then(res => res.toString());
|
|
178
|
+
}
|
|
179
|
+
async getProfileS3(s3path) {
|
|
180
|
+
if (!s3path) {
|
|
181
|
+
throw new Error('s3path not found');
|
|
182
|
+
}
|
|
183
|
+
const token = this.access_token;
|
|
184
|
+
debug('getProfileS3 token=', token, 'profile=', this.profile_id, 's3path=', s3path);
|
|
185
|
+
const downloadURL = `${_constants.STORAGE_GATEWAY_BASE_URL}/download`;
|
|
186
|
+
debug('loading profile from public s3 bucket, url=', downloadURL);
|
|
187
|
+
const profileResponse = await _requestretry.default.get(downloadURL, {
|
|
188
|
+
encoding: null,
|
|
189
|
+
headers: {
|
|
190
|
+
Authorization: `Bearer ${token}`,
|
|
191
|
+
browserId: this.profile_id
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
if (profileResponse.statusCode !== 200) {
|
|
195
|
+
debug(`Gologin S3 BUCKET ${downloadURL} response error ${profileResponse.statusCode} - use empty`);
|
|
196
|
+
return '';
|
|
197
|
+
}
|
|
198
|
+
return Buffer.from(profileResponse.body);
|
|
199
|
+
}
|
|
200
|
+
async postFile(fileName, fileBuff) {
|
|
201
|
+
debug('POSTING FILE', fileBuff.length);
|
|
202
|
+
debug('Getting signed URL for S3');
|
|
203
|
+
const apiUrl = `${_constants.STORAGE_GATEWAY_BASE_URL}/upload`;
|
|
204
|
+
const bodyBufferBiteLength = Buffer.byteLength(fileBuff);
|
|
205
|
+
console.log('BUFFER SIZE', bodyBufferBiteLength);
|
|
206
|
+
await _requestretry.default.put(apiUrl, {
|
|
207
|
+
headers: {
|
|
208
|
+
Authorization: `Bearer ${this.access_token}`,
|
|
209
|
+
browserId: this.profile_id,
|
|
210
|
+
'Content-Type': 'application/zip',
|
|
211
|
+
'Content-Length': bodyBufferBiteLength
|
|
212
|
+
},
|
|
213
|
+
body: fileBuff,
|
|
214
|
+
maxBodyLength: Infinity,
|
|
215
|
+
maxContentLength: Infinity,
|
|
216
|
+
maxAttempts: 3,
|
|
217
|
+
retryDelay: 2000,
|
|
218
|
+
timeout: 30 * 1000,
|
|
219
|
+
fullResponse: false
|
|
220
|
+
});
|
|
221
|
+
console.log('Profile has been uploaded to S3 successfully');
|
|
222
|
+
}
|
|
223
|
+
async emptyProfileFolder() {
|
|
224
|
+
debug('get emptyProfileFolder');
|
|
225
|
+
const currentDir = (0, _path.dirname)(new URL(require('url').pathToFileURL(__filename).toString()).pathname);
|
|
226
|
+
const zeroProfilePath = (0, _path.join)(currentDir, '..', 'zero_profile.zip');
|
|
227
|
+
const profile = await readFile((0, _path.resolve)(zeroProfilePath));
|
|
228
|
+
debug('emptyProfileFolder LENGTH ::', profile.length);
|
|
229
|
+
return profile;
|
|
230
|
+
}
|
|
231
|
+
convertPreferences(preferences) {
|
|
232
|
+
if ((0, _utils2.get)(preferences, 'navigator.userAgent')) {
|
|
233
|
+
preferences.userAgent = (0, _utils2.get)(preferences, 'navigator.userAgent');
|
|
234
|
+
}
|
|
235
|
+
if ((0, _utils2.get)(preferences, 'navigator.doNotTrack')) {
|
|
236
|
+
preferences.doNotTrack = (0, _utils2.get)(preferences, 'navigator.doNotTrack');
|
|
237
|
+
}
|
|
238
|
+
if ((0, _utils2.get)(preferences, 'navigator.hardwareConcurrency')) {
|
|
239
|
+
preferences.hardwareConcurrency = (0, _utils2.get)(preferences, 'navigator.hardwareConcurrency');
|
|
240
|
+
}
|
|
241
|
+
if ((0, _utils2.get)(preferences, 'navigator.deviceMemory')) {
|
|
242
|
+
preferences.deviceMemory = (0, _utils2.get)(preferences, 'navigator.deviceMemory') * 1024;
|
|
243
|
+
}
|
|
244
|
+
if ((0, _utils2.get)(preferences, 'navigator.language')) {
|
|
245
|
+
preferences.langHeader = (0, _utils2.get)(preferences, 'navigator.language');
|
|
246
|
+
preferences.languages = (0, _utils2.get)(preferences, 'navigator.language').replace(/;|q=[\d\.]+/img, '');
|
|
247
|
+
}
|
|
248
|
+
if ((0, _utils2.get)(preferences, 'navigator.maxTouchPoints')) {
|
|
249
|
+
preferences.navigator.max_touch_points = (0, _utils2.get)(preferences, 'navigator.maxTouchPoints');
|
|
250
|
+
}
|
|
251
|
+
if ((0, _utils2.get)(preferences, 'isM1')) {
|
|
252
|
+
preferences.is_m1 = (0, _utils2.get)(preferences, 'isM1');
|
|
253
|
+
}
|
|
254
|
+
if ((0, _utils2.get)(preferences, 'os') == 'android') {
|
|
255
|
+
const devicePixelRatio = (0, _utils2.get)(preferences, 'devicePixelRatio');
|
|
256
|
+
const deviceScaleFactorCeil = Math.ceil(devicePixelRatio || 3.5);
|
|
257
|
+
let deviceScaleFactor = devicePixelRatio;
|
|
258
|
+
if (deviceScaleFactorCeil === devicePixelRatio) {
|
|
259
|
+
deviceScaleFactor += 0.00000001;
|
|
260
|
+
}
|
|
261
|
+
preferences.mobile = {
|
|
262
|
+
enable: true,
|
|
263
|
+
width: parseInt(this.resolution.width, 10),
|
|
264
|
+
height: parseInt(this.resolution.height, 10),
|
|
265
|
+
device_scale_factor: deviceScaleFactor
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
preferences.mediaDevices = {
|
|
269
|
+
enable: preferences.mediaDevices.enableMasking,
|
|
270
|
+
videoInputs: preferences.mediaDevices.videoInputs,
|
|
271
|
+
audioInputs: preferences.mediaDevices.audioInputs,
|
|
272
|
+
audioOutputs: preferences.mediaDevices.audioOutputs
|
|
273
|
+
};
|
|
274
|
+
preferences.webRtc = {
|
|
275
|
+
...preferences.webRtc,
|
|
276
|
+
fill_based_on_ip: !!(0, _utils2.get)(preferences, 'webRTC.fillBasedOnIp'),
|
|
277
|
+
local_ip_masking: !!(0, _utils2.get)(preferences, 'webRTC.local_ip_masking')
|
|
278
|
+
};
|
|
279
|
+
return preferences;
|
|
280
|
+
}
|
|
281
|
+
async createBrowserExtension() {
|
|
282
|
+
const that = this;
|
|
283
|
+
debug('start createBrowserExtension');
|
|
284
|
+
await (0, _rimraf.default)(this.orbitaExtensionPath(), () => null);
|
|
285
|
+
const extPath = this.orbitaExtensionPath();
|
|
286
|
+
debug('extension folder sanitized');
|
|
287
|
+
const extension_source = (0, _path.resolve)(__dirname, 'gologin-browser-ext.zip');
|
|
288
|
+
await (0, _decompress.default)(extension_source, extPath, {
|
|
289
|
+
plugins: [(0, _decompressUnzip.default)()],
|
|
290
|
+
filter: file => !file.path.endsWith('/')
|
|
291
|
+
}).then(() => {
|
|
292
|
+
debug('extraction done');
|
|
293
|
+
debug('create uid.json');
|
|
294
|
+
return writeFile((0, _path.join)(extPath, 'uid.json'), JSON.stringify({
|
|
295
|
+
uid: that.profile_id
|
|
296
|
+
}, null, 2)).then(() => extPath);
|
|
297
|
+
}).catch(async e => {
|
|
298
|
+
debug('orbita extension error', e);
|
|
299
|
+
});
|
|
300
|
+
debug('createBrowserExtension done');
|
|
301
|
+
}
|
|
302
|
+
extractProfile(path, zipfile) {
|
|
303
|
+
debug(`extactProfile ${zipfile}, ${path}`);
|
|
304
|
+
return (0, _decompress.default)(zipfile, path, {
|
|
305
|
+
plugins: [(0, _decompressUnzip.default)()],
|
|
306
|
+
filter: file => !file.path.endsWith('/')
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
async createStartup(local = false) {
|
|
310
|
+
const profilePath = (0, _path.join)(this.tmpdir, `gologin_profile_${this.profile_id}`);
|
|
311
|
+
let profile;
|
|
312
|
+
let profile_folder;
|
|
313
|
+
await (0, _rimraf.default)(profilePath, () => null);
|
|
314
|
+
debug('-', profilePath, 'dropped');
|
|
315
|
+
profile = await this.getProfile();
|
|
316
|
+
const {
|
|
317
|
+
navigator = {},
|
|
318
|
+
fonts,
|
|
319
|
+
os: profileOs
|
|
320
|
+
} = profile;
|
|
321
|
+
this.fontsMasking = fonts?.enableMasking;
|
|
322
|
+
this.profileOs = profileOs;
|
|
323
|
+
this.differentOs = profileOs !== 'android' && (OS_PLATFORM === 'win32' && profileOs !== 'win' || OS_PLATFORM === 'darwin' && profileOs !== 'mac' || OS_PLATFORM === 'linux' && profileOs !== 'lin');
|
|
324
|
+
const {
|
|
325
|
+
resolution = '1920x1080',
|
|
326
|
+
language = 'en-US,en;q=0.9'
|
|
327
|
+
} = navigator;
|
|
328
|
+
this.language = language;
|
|
329
|
+
const [screenWidth, screenHeight] = resolution.split('x');
|
|
330
|
+
this.resolution = {
|
|
331
|
+
width: parseInt(screenWidth, 10),
|
|
332
|
+
height: parseInt(screenHeight, 10)
|
|
333
|
+
};
|
|
334
|
+
const profileZipExists = await access(this.profile_zip_path).then(() => true).catch(() => false);
|
|
335
|
+
if (!(local && profileZipExists)) {
|
|
336
|
+
try {
|
|
337
|
+
profile_folder = await this.getProfileS3((0, _utils2.get)(profile, 's3Path', ''));
|
|
338
|
+
} catch (e) {
|
|
339
|
+
debug('Cannot get profile - using empty', e);
|
|
340
|
+
}
|
|
341
|
+
debug('FILE READY', this.profile_zip_path);
|
|
342
|
+
if (!profile_folder.length) {
|
|
343
|
+
profile_folder = await this.emptyProfileFolder();
|
|
344
|
+
}
|
|
345
|
+
await writeFile(this.profile_zip_path, profile_folder);
|
|
346
|
+
debug('PROFILE LENGTH', profile_folder.length);
|
|
347
|
+
} else {
|
|
348
|
+
debug('PROFILE LOCAL HAVING', this.profile_zip_path);
|
|
349
|
+
}
|
|
350
|
+
debug('Cleaning up..', profilePath);
|
|
351
|
+
try {
|
|
352
|
+
await this.extractProfile(profilePath, this.profile_zip_path);
|
|
353
|
+
debug('extraction done');
|
|
354
|
+
} catch (e) {
|
|
355
|
+
console.trace(e);
|
|
356
|
+
profile_folder = await this.emptyProfileFolder();
|
|
357
|
+
await writeFile(this.profile_zip_path, profile_folder);
|
|
358
|
+
await this.extractProfile(profilePath, this.profile_zip_path);
|
|
359
|
+
}
|
|
360
|
+
const singletonLockPath = (0, _path.join)(profilePath, 'SingletonLock');
|
|
361
|
+
const singletonLockExists = await access(singletonLockPath).then(() => true).catch(() => false);
|
|
362
|
+
if (singletonLockExists) {
|
|
363
|
+
debug('removing SingletonLock');
|
|
364
|
+
await unlink(singletonLockPath);
|
|
365
|
+
debug('SingletonLock removed');
|
|
366
|
+
}
|
|
367
|
+
const pref_file_name = (0, _path.join)(profilePath, 'Default', 'Preferences');
|
|
368
|
+
debug('reading', pref_file_name);
|
|
369
|
+
const prefFileExists = await access(pref_file_name).then(() => true).catch(() => false);
|
|
370
|
+
if (!prefFileExists) {
|
|
371
|
+
debug('Preferences file not exists waiting', pref_file_name, '. Using empty profile');
|
|
372
|
+
profile_folder = await this.emptyProfileFolder();
|
|
373
|
+
await writeFile(this.profile_zip_path, profile_folder);
|
|
374
|
+
await this.extractProfile(profilePath, this.profile_zip_path);
|
|
375
|
+
await writeFile(pref_file_name, '{}');
|
|
376
|
+
}
|
|
377
|
+
const preferences_raw = await readFile(pref_file_name);
|
|
378
|
+
const preferences = JSON.parse(preferences_raw.toString());
|
|
379
|
+
let proxy = (0, _utils2.get)(profile, 'proxy');
|
|
380
|
+
const name = (0, _utils2.get)(profile, 'name');
|
|
381
|
+
const chromeExtensions = (0, _utils2.get)(profile, 'chromeExtensions') || [];
|
|
382
|
+
const userChromeExtensions = (0, _utils2.get)(profile, 'userChromeExtensions') || [];
|
|
383
|
+
const allExtensions = [...chromeExtensions, ...userChromeExtensions];
|
|
384
|
+
if (allExtensions.length) {
|
|
385
|
+
const ExtensionsManagerInst = new _extensionsManager.default();
|
|
386
|
+
ExtensionsManagerInst.apiUrl = _common.API_URL;
|
|
387
|
+
await ExtensionsManagerInst.init().then(() => ExtensionsManagerInst.updateExtensions()).catch(() => {});
|
|
388
|
+
ExtensionsManagerInst.accessToken = this.access_token;
|
|
389
|
+
await ExtensionsManagerInst.getExtensionsPolicies();
|
|
390
|
+
let profileExtensionsCheckRes = [];
|
|
391
|
+
if (ExtensionsManagerInst.useLocalExtStorage) {
|
|
392
|
+
const promises = [ExtensionsManagerInst.checkChromeExtensions(allExtensions).then(res => ({
|
|
393
|
+
profileExtensionsCheckRes: res
|
|
394
|
+
})).catch(e => {
|
|
395
|
+
console.log('checkChromeExtensions error: ', e);
|
|
396
|
+
return {
|
|
397
|
+
profileExtensionsCheckRes: []
|
|
398
|
+
};
|
|
399
|
+
}), ExtensionsManagerInst.checkLocalUserChromeExtensions(userChromeExtensions, this.profile_id).then(res => ({
|
|
400
|
+
profileUserExtensionsCheckRes: res
|
|
401
|
+
})).catch(error => {
|
|
402
|
+
console.log('checkUserChromeExtensions error: ', error);
|
|
403
|
+
return null;
|
|
404
|
+
})];
|
|
405
|
+
const extensionsResult = await Promise.all(promises);
|
|
406
|
+
const profileExtensionPathRes = extensionsResult.find(el => 'profileExtensionsCheckRes' in el) || {};
|
|
407
|
+
const profileUserExtensionPathRes = extensionsResult.find(el => 'profileUserExtensionsCheckRes' in el);
|
|
408
|
+
profileExtensionsCheckRes = (profileExtensionPathRes?.profileExtensionsCheckRes || []).concat(profileUserExtensionPathRes?.profileUserExtensionsCheckRes || []);
|
|
409
|
+
}
|
|
410
|
+
let extSettings;
|
|
411
|
+
if (ExtensionsManagerInst.useLocalExtStorage) {
|
|
412
|
+
extSettings = await (0, _browserUserDataManager.setExtPathsAndRemoveDeleted)(preferences, profileExtensionsCheckRes, this.profile_id);
|
|
413
|
+
} else {
|
|
414
|
+
const originalExtensionsFolder = (0, _path.join)(profilePath, 'Default', 'Extensions');
|
|
415
|
+
extSettings = await (0, _browserUserDataManager.setOriginalExtPaths)(preferences, originalExtensionsFolder);
|
|
416
|
+
}
|
|
417
|
+
this.extensionPathsToInstall = ExtensionsManagerInst.getExtensionsToInstall(extSettings, profileExtensionsCheckRes);
|
|
418
|
+
if (extSettings) {
|
|
419
|
+
const currentExtSettings = preferences.extensions || {};
|
|
420
|
+
currentExtSettings.settings = extSettings;
|
|
421
|
+
preferences.extensions = currentExtSettings;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (proxy.mode === 'gologin' || proxy.mode === 'tor') {
|
|
425
|
+
const autoProxyServer = (0, _utils2.get)(profile, 'autoProxyServer');
|
|
426
|
+
const splittedAutoProxyServer = autoProxyServer.split('://');
|
|
427
|
+
const splittedProxyAddress = splittedAutoProxyServer[1].split(':');
|
|
428
|
+
const port = splittedProxyAddress[1];
|
|
429
|
+
proxy = {
|
|
430
|
+
'mode': splittedAutoProxyServer[0],
|
|
431
|
+
'host': splittedProxyAddress[0],
|
|
432
|
+
port,
|
|
433
|
+
'username': (0, _utils2.get)(profile, 'autoProxyUsername'),
|
|
434
|
+
'password': (0, _utils2.get)(profile, 'autoProxyPassword')
|
|
435
|
+
};
|
|
436
|
+
profile.proxy.username = (0, _utils2.get)(profile, 'autoProxyUsername');
|
|
437
|
+
profile.proxy.password = (0, _utils2.get)(profile, 'autoProxyPassword');
|
|
438
|
+
}
|
|
439
|
+
if (proxy.mode === 'geolocation') {
|
|
440
|
+
proxy.mode = 'http';
|
|
441
|
+
}
|
|
442
|
+
if (proxy.mode === PROXY_NONE) {
|
|
443
|
+
proxy = null;
|
|
444
|
+
}
|
|
445
|
+
this.proxy = proxy;
|
|
446
|
+
await this.getTimeZone(proxy).catch(e => {
|
|
447
|
+
console.error('Proxy Error. Check it and try again.');
|
|
448
|
+
throw e;
|
|
449
|
+
});
|
|
450
|
+
const [latitude, longitude] = this._tz.ll;
|
|
451
|
+
const {
|
|
452
|
+
accuracy
|
|
453
|
+
} = this._tz;
|
|
454
|
+
const profileGeolocation = profile.geolocation;
|
|
455
|
+
const tzGeoLocation = {
|
|
456
|
+
latitude,
|
|
457
|
+
longitude,
|
|
458
|
+
accuracy
|
|
459
|
+
};
|
|
460
|
+
profile.geoLocation = this.getGeolocationParams(profileGeolocation, tzGeoLocation);
|
|
461
|
+
profile.name = name;
|
|
462
|
+
profile.name_base64 = Buffer.from(name).toString('base64');
|
|
463
|
+
profile.profile_id = this.profile_id;
|
|
464
|
+
profile.webRtc = {
|
|
465
|
+
mode: (0, _utils2.get)(profile, 'webRTC.mode') === 'alerted' ? 'public' : (0, _utils2.get)(profile, 'webRTC.mode'),
|
|
466
|
+
publicIP: (0, _utils2.get)(profile, 'webRTC.fillBasedOnIp') ? this._tz.ip : (0, _utils2.get)(profile, 'webRTC.publicIp'),
|
|
467
|
+
localIps: (0, _utils2.get)(profile, 'webRTC.localIps', [])
|
|
468
|
+
};
|
|
469
|
+
debug('profile.webRtc=', profile.webRtc);
|
|
470
|
+
debug('profile.timezone=', profile.timezone);
|
|
471
|
+
debug('profile.mediaDevices=', profile.mediaDevices);
|
|
472
|
+
const audioContext = profile.audioContext || {};
|
|
473
|
+
const {
|
|
474
|
+
mode: audioCtxMode = 'off',
|
|
475
|
+
noise: audioCtxNoise
|
|
476
|
+
} = audioContext;
|
|
477
|
+
if (profile.timezone.fillBasedOnIp === false) {
|
|
478
|
+
profile.timezone = {
|
|
479
|
+
id: profile.timezone.timezone
|
|
480
|
+
};
|
|
481
|
+
} else {
|
|
482
|
+
profile.timezone = {
|
|
483
|
+
id: this._tz.timezone
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
profile.webgl_noise_value = profile.webGL.noise;
|
|
487
|
+
profile.get_client_rects_noise = profile.webGL.getClientRectsNoise;
|
|
488
|
+
profile.canvasMode = profile.canvas.mode;
|
|
489
|
+
profile.canvasNoise = profile.canvas.noise;
|
|
490
|
+
profile.audioContext = {
|
|
491
|
+
enable: audioCtxMode !== 'off',
|
|
492
|
+
noiseValue: audioCtxNoise
|
|
493
|
+
};
|
|
494
|
+
profile.webgl = {
|
|
495
|
+
metadata: {
|
|
496
|
+
vendor: (0, _utils2.get)(profile, 'webGLMetadata.vendor'),
|
|
497
|
+
renderer: (0, _utils2.get)(profile, 'webGLMetadata.renderer'),
|
|
498
|
+
mode: (0, _utils2.get)(profile, 'webGLMetadata.mode') === 'mask'
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
profile.custom_fonts = {
|
|
502
|
+
enable: !!fonts?.enableMasking
|
|
503
|
+
};
|
|
504
|
+
const gologin = this.convertPreferences(profile);
|
|
505
|
+
debug(`Writing profile for screenWidth ${profilePath}`, JSON.stringify(gologin));
|
|
506
|
+
gologin.screenWidth = this.resolution.width;
|
|
507
|
+
gologin.screenHeight = this.resolution.height;
|
|
508
|
+
debug('writeCookiesFromServer', this.writeCookiesFromServer);
|
|
509
|
+
this.cookiesFilePath = await (0, _cookiesManager.getCookiesFilePath)(this.profile_id, this.tmpdir);
|
|
510
|
+
if (this.writeCookiesFromServer) {
|
|
511
|
+
await this.writeCookiesToFile();
|
|
512
|
+
}
|
|
513
|
+
if (this.fontsMasking) {
|
|
514
|
+
const families = fonts?.families || [];
|
|
515
|
+
if (!families.length) {
|
|
516
|
+
throw new Error('No fonts list provided');
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
await (0, _browserUserDataManager.composeFonts)(families, profilePath, this.differentOs);
|
|
520
|
+
} catch (e) {
|
|
521
|
+
console.trace(e);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
const languages = this.language.replace(/;|q=[\d\.]+/img, '');
|
|
525
|
+
if (preferences.gologin == null) {
|
|
526
|
+
preferences.gologin = {};
|
|
527
|
+
}
|
|
528
|
+
preferences.gologin.langHeader = gologin.navigator.language;
|
|
529
|
+
preferences.gologin.language = languages;
|
|
530
|
+
const [splittedLangs] = gologin.navigator.language.split(';');
|
|
531
|
+
const [browserLang] = splittedLangs.split(',');
|
|
532
|
+
gologin.browserLang = browserLang;
|
|
533
|
+
const isMAC = OS_PLATFORM === 'darwin';
|
|
534
|
+
const checkAutoLangResult = (0, _browser.checkAutoLang)(gologin, this._tz);
|
|
535
|
+
this.browserLang = isMAC ? 'en-US' : checkAutoLangResult;
|
|
536
|
+
await writeFile((0, _path.join)(profilePath, 'Default', 'Preferences'), JSON.stringify(Object.assign(preferences, {
|
|
537
|
+
gologin
|
|
538
|
+
})));
|
|
539
|
+
const bookmarksParsedData = await (0, _utils.getCurrentProfileBookmarks)(this.bookmarksFilePath);
|
|
540
|
+
const bookmarksFromDb = profile.bookmarks?.bookmark_bar;
|
|
541
|
+
bookmarksParsedData.roots = bookmarksFromDb ? profile.bookmarks : bookmarksParsedData.roots;
|
|
542
|
+
await writeFile(this.bookmarksFilePath, JSON.stringify(bookmarksParsedData));
|
|
543
|
+
debug('Profile ready. Path: ', profilePath, 'PROXY', JSON.stringify((0, _utils2.get)(preferences, 'gologin.proxy')));
|
|
544
|
+
return profilePath;
|
|
545
|
+
}
|
|
546
|
+
async commitProfile() {
|
|
547
|
+
const dataBuff = await this.getProfileDataToUpdate();
|
|
548
|
+
debug('begin updating', dataBuff.length);
|
|
549
|
+
if (!dataBuff.length) {
|
|
550
|
+
debug('WARN: profile zip data empty - SKIPPING PROFILE COMMIT');
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
try {
|
|
554
|
+
debug('Patching profile');
|
|
555
|
+
await this.postFile('profile', dataBuff);
|
|
556
|
+
} catch (e) {
|
|
557
|
+
debug('CANNOT COMMIT PROFILE', e);
|
|
558
|
+
}
|
|
559
|
+
debug('COMMIT COMPLETED');
|
|
560
|
+
}
|
|
561
|
+
profilePath() {
|
|
562
|
+
return (0, _path.join)(this.tmpdir, `gologin_profile_${this.profile_id}`);
|
|
563
|
+
}
|
|
564
|
+
orbitaExtensionPath() {
|
|
565
|
+
return (0, _path.join)(this.tmpdir, `orbita_extension_${this.profile_id}`);
|
|
566
|
+
}
|
|
567
|
+
getRandomInt(min, max) {
|
|
568
|
+
min = Math.ceil(min);
|
|
569
|
+
max = Math.floor(max);
|
|
570
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
571
|
+
}
|
|
572
|
+
async checkPortAvailable(port) {
|
|
573
|
+
debug('CHECKING PORT AVAILABLE', port);
|
|
574
|
+
try {
|
|
575
|
+
const portAvailable = await (0, _utils2.isPortReachable)(port, {
|
|
576
|
+
host: 'localhost'
|
|
577
|
+
});
|
|
578
|
+
if (portAvailable) {
|
|
579
|
+
debug(`PORT ${port} IS OPEN`);
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
} catch (e) {
|
|
583
|
+
console.log(e);
|
|
584
|
+
}
|
|
585
|
+
debug(`PORT ${port} IS BUSY`);
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
async getRandomPort() {
|
|
589
|
+
let port = this.getRandomInt(20000, 40000);
|
|
590
|
+
let portAvailable = await this.checkPortAvailable(port);
|
|
591
|
+
while (!portAvailable) {
|
|
592
|
+
port = this.getRandomInt(20000, 40000);
|
|
593
|
+
portAvailable = await this.checkPortAvailable(port);
|
|
594
|
+
}
|
|
595
|
+
return port;
|
|
596
|
+
}
|
|
597
|
+
async getTimeZone(proxy) {
|
|
598
|
+
debug('getting timeZone proxy=', proxy);
|
|
599
|
+
if (this.timezone) {
|
|
600
|
+
debug('getTimeZone from options', this.timezone);
|
|
601
|
+
this._tz = this.timezone;
|
|
602
|
+
return this._tz.timezone;
|
|
603
|
+
}
|
|
604
|
+
let data = null;
|
|
605
|
+
if (proxy && proxy.mode !== PROXY_NONE) {
|
|
606
|
+
if (proxy.mode.includes('socks')) {
|
|
607
|
+
for (let i = 0; i < 5; i++) {
|
|
608
|
+
try {
|
|
609
|
+
debug('getting timeZone socks try', i + 1);
|
|
610
|
+
return this.getTimezoneWithSocks(proxy);
|
|
611
|
+
} catch (e) {
|
|
612
|
+
console.log(e.message);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
throw new Error('Socks proxy connection timed out');
|
|
616
|
+
}
|
|
617
|
+
const proxyUrl = `${proxy.mode}://${proxy.username}:${proxy.password}@${proxy.host}:${proxy.port}`;
|
|
618
|
+
debug(`getTimeZone start ${TIMEZONE_URL}`, proxyUrl);
|
|
619
|
+
data = await _requestretry.default.get(TIMEZONE_URL, {
|
|
620
|
+
proxy: proxyUrl,
|
|
621
|
+
timeout: 20 * 1000,
|
|
622
|
+
maxAttempts: 5
|
|
623
|
+
});
|
|
624
|
+
} else {
|
|
625
|
+
data = await _requestretry.default.get(TIMEZONE_URL, {
|
|
626
|
+
timeout: 20 * 1000,
|
|
627
|
+
maxAttempts: 5
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
debug('getTimeZone finish', data.body);
|
|
631
|
+
this._tz = JSON.parse(data.body);
|
|
632
|
+
return this._tz.timezone;
|
|
633
|
+
}
|
|
634
|
+
async getTimezoneWithSocks(params) {
|
|
635
|
+
const {
|
|
636
|
+
host,
|
|
637
|
+
port,
|
|
638
|
+
username = '',
|
|
639
|
+
password = ''
|
|
640
|
+
} = params;
|
|
641
|
+
let body;
|
|
642
|
+
let proxy = 'socks://';
|
|
643
|
+
if (username) {
|
|
644
|
+
const resultPassword = password ? ':' + password + '@' : '@';
|
|
645
|
+
proxy += username + resultPassword;
|
|
646
|
+
}
|
|
647
|
+
proxy += host + ':' + port;
|
|
648
|
+
const agent = new _socksProxyAgent.SocksProxyAgent(proxy);
|
|
649
|
+
const checkData = await new Promise((resolve, reject) => {
|
|
650
|
+
(0, _https.get)(TIMEZONE_URL, {
|
|
651
|
+
agent,
|
|
652
|
+
timeout: 10000
|
|
653
|
+
}, res => {
|
|
654
|
+
let resultResponse = '';
|
|
655
|
+
res.on('data', data => resultResponse += data);
|
|
656
|
+
res.on('end', () => {
|
|
657
|
+
let parsedData;
|
|
658
|
+
try {
|
|
659
|
+
parsedData = JSON.parse(resultResponse);
|
|
660
|
+
} catch (e) {
|
|
661
|
+
reject(e);
|
|
662
|
+
}
|
|
663
|
+
resolve({
|
|
664
|
+
...res,
|
|
665
|
+
body: parsedData
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
}).on('error', err => reject(err));
|
|
669
|
+
});
|
|
670
|
+
body = checkData.body || {};
|
|
671
|
+
if (!body.ip && checkData.statusCode.toString().startsWith('4')) {
|
|
672
|
+
throw checkData;
|
|
673
|
+
}
|
|
674
|
+
debug('getTimeZone finish', body.body);
|
|
675
|
+
this._tz = body;
|
|
676
|
+
return this._tz.timezone;
|
|
677
|
+
}
|
|
678
|
+
async spawnArguments() {
|
|
679
|
+
const profile_path = this.profilePath();
|
|
680
|
+
let {
|
|
681
|
+
proxy
|
|
682
|
+
} = this;
|
|
683
|
+
proxy = `${proxy.mode}://${proxy.host}:${proxy.port}`;
|
|
684
|
+
const env = {};
|
|
685
|
+
Object.keys(process.env).forEach(key => {
|
|
686
|
+
env[key] = process.env[key];
|
|
687
|
+
});
|
|
688
|
+
const tz = await this.getTimeZone(this.proxy).catch(e => {
|
|
689
|
+
console.error('Proxy Error. Check it and try again.');
|
|
690
|
+
throw e;
|
|
691
|
+
});
|
|
692
|
+
env.TZ = tz;
|
|
693
|
+
let params = [`--proxy-server=${proxy}`, `--user-data-dir=${profile_path}`, '--password-store=basic', `--tz=${tz}`, '--lang=en'];
|
|
694
|
+
if (Array.isArray(this.extra_params) && this.extra_params.length) {
|
|
695
|
+
params = params.concat(this.extra_params);
|
|
696
|
+
}
|
|
697
|
+
if (this.remote_debugging_port) {
|
|
698
|
+
params.push(`--remote-debugging-port=${this.remote_debugging_port}`);
|
|
699
|
+
}
|
|
700
|
+
return params;
|
|
701
|
+
}
|
|
702
|
+
async spawnBrowser() {
|
|
703
|
+
let {
|
|
704
|
+
remote_debugging_port,
|
|
705
|
+
customArgs
|
|
706
|
+
} = this;
|
|
707
|
+
if (!remote_debugging_port) {
|
|
708
|
+
remote_debugging_port = await this.getRandomPort();
|
|
709
|
+
}
|
|
710
|
+
const profile_path = this.profilePath();
|
|
711
|
+
let {
|
|
712
|
+
proxy
|
|
713
|
+
} = this;
|
|
714
|
+
let proxy_host = '';
|
|
715
|
+
if (proxy) {
|
|
716
|
+
proxy_host = this.proxy.host;
|
|
717
|
+
proxy = `${proxy.mode}://${proxy.host}:${proxy.port}`;
|
|
718
|
+
}
|
|
719
|
+
this.port = remote_debugging_port;
|
|
720
|
+
const ORBITA_BROWSER = this.executablePath || this.browserChecker.getOrbitaPath;
|
|
721
|
+
debug(`ORBITA_BROWSER=${ORBITA_BROWSER}`);
|
|
722
|
+
const env = {};
|
|
723
|
+
Object.keys(process.env).forEach(key => {
|
|
724
|
+
env[key] = process.env[key];
|
|
725
|
+
});
|
|
726
|
+
const tz = await this.getTimeZone(this.proxy).catch(e => {
|
|
727
|
+
console.error('Proxy Error. Check it and try again.');
|
|
728
|
+
throw e;
|
|
729
|
+
});
|
|
730
|
+
env.TZ = tz;
|
|
731
|
+
if (this.vnc_port) {
|
|
732
|
+
const script_path = (0, _path.resolve)(__dirname, './run.sh');
|
|
733
|
+
debug('RUNNING', script_path, ORBITA_BROWSER, remote_debugging_port, proxy, profile_path, this.vnc_port);
|
|
734
|
+
(0, _child_process.execFile)(script_path, [ORBITA_BROWSER, remote_debugging_port, proxy, profile_path, this.vnc_port, tz], {
|
|
735
|
+
env
|
|
736
|
+
});
|
|
737
|
+
} else {
|
|
738
|
+
let params = [`--remote-debugging-port=${remote_debugging_port}`, `--user-data-dir=${profile_path}`, '--password-store=basic', `--tz=${tz}`, `--lang=${this.browserLang}`];
|
|
739
|
+
if (this.extensionPathsToInstall.length) {
|
|
740
|
+
if (Array.isArray(this.extra_params) && this.extra_params.length) {
|
|
741
|
+
this.extra_params.forEach((param, index) => {
|
|
742
|
+
if (!param.includes('--load-extension=')) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
const [_, extPathsString] = param.split('=');
|
|
746
|
+
const extPathsArray = extPathsString.split(',');
|
|
747
|
+
this.extensionPathsToInstall = [...this.extensionPathsToInstall, ...extPathsArray];
|
|
748
|
+
this.extra_params.splice(index, 1);
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
params.push(`--load-extension=${this.extensionPathsToInstall.join(',')}`);
|
|
752
|
+
}
|
|
753
|
+
if (this.fontsMasking) {
|
|
754
|
+
let arg = '--font-masking-mode=2';
|
|
755
|
+
if (this.differentOs) {
|
|
756
|
+
arg = '--font-masking-mode=3';
|
|
757
|
+
}
|
|
758
|
+
if (this.profileOs === 'android') {
|
|
759
|
+
arg = '--font-masking-mode=1';
|
|
760
|
+
}
|
|
761
|
+
params.push(arg);
|
|
762
|
+
}
|
|
763
|
+
if (proxy) {
|
|
764
|
+
const hr_rules = `"MAP * 0.0.0.0 , EXCLUDE ${proxy_host}"`;
|
|
765
|
+
params.push(`--proxy-server=${proxy}`);
|
|
766
|
+
params.push(`--host-resolver-rules=${hr_rules}`);
|
|
767
|
+
}
|
|
768
|
+
if (Array.isArray(this.extra_params) && this.extra_params.length) {
|
|
769
|
+
params = params.concat(this.extra_params);
|
|
770
|
+
}
|
|
771
|
+
if (this.restoreLastSession) {
|
|
772
|
+
params.push('--restore-last-session');
|
|
773
|
+
}
|
|
774
|
+
params.push(...new Set(customArgs));
|
|
775
|
+
console.log(params);
|
|
776
|
+
const child = (0, _child_process.execFile)(ORBITA_BROWSER, params, {
|
|
777
|
+
env
|
|
778
|
+
});
|
|
779
|
+
this.processSpawned = child;
|
|
780
|
+
// const child = spawn(ORBITA_BROWSER, params, { env, shell: true });
|
|
781
|
+
child.stdout.on('data', data => debug(data.toString()));
|
|
782
|
+
debug('SPAWN CMD', ORBITA_BROWSER, params.join(' '));
|
|
783
|
+
}
|
|
784
|
+
if (this.waitWebsocket) {
|
|
785
|
+
debug('GETTING WS URL FROM BROWSER');
|
|
786
|
+
const data = await _requestretry.default.get(`http://127.0.0.1:${remote_debugging_port}/json/version`, {
|
|
787
|
+
json: true
|
|
788
|
+
});
|
|
789
|
+
debug('WS IS', (0, _utils2.get)(data, 'body.webSocketDebuggerUrl', ''));
|
|
790
|
+
this.is_active = true;
|
|
791
|
+
return (0, _utils2.get)(data, 'body.webSocketDebuggerUrl', '');
|
|
792
|
+
}
|
|
793
|
+
return '';
|
|
794
|
+
}
|
|
795
|
+
async createStartupAndSpawnBrowser() {
|
|
796
|
+
await this.createStartup();
|
|
797
|
+
return this.spawnBrowser();
|
|
798
|
+
}
|
|
799
|
+
async clearProfileFiles() {
|
|
800
|
+
await (0, _rimraf.default)((0, _path.join)(this.tmpdir, `gologin_profile_${this.profile_id}`), () => null);
|
|
801
|
+
await (0, _rimraf.default)((0, _path.join)(this.tmpdir, `gologin_${this.profile_id}_upload.zip`), () => null);
|
|
802
|
+
}
|
|
803
|
+
async stopAndCommit(options, local = false) {
|
|
804
|
+
if (this.is_stopping) {
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
const is_posting = options.posting || options.postings ||
|
|
808
|
+
// backward compability
|
|
809
|
+
false;
|
|
810
|
+
if (this.uploadCookiesToServer) {
|
|
811
|
+
await this.uploadProfileCookiesToServer();
|
|
812
|
+
}
|
|
813
|
+
await this.saveBookmarksToDb();
|
|
814
|
+
this.is_stopping = true;
|
|
815
|
+
await this.sanitizeProfile();
|
|
816
|
+
if (is_posting) {
|
|
817
|
+
await this.commitProfile();
|
|
818
|
+
}
|
|
819
|
+
this.is_stopping = false;
|
|
820
|
+
this.is_active = false;
|
|
821
|
+
await delay(3000);
|
|
822
|
+
await this.clearProfileFiles();
|
|
823
|
+
if (!local) {
|
|
824
|
+
await (0, _rimraf.default)((0, _path.join)(this.tmpdir, `gologin_${this.profile_id}.zip`), () => null);
|
|
825
|
+
}
|
|
826
|
+
debug(`PROFILE ${this.profile_id} STOPPED AND CLEAR`);
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
async stopBrowser() {
|
|
830
|
+
if (!this.port) {
|
|
831
|
+
throw new Error('Empty GoLogin port');
|
|
832
|
+
}
|
|
833
|
+
const ls = await (0, _child_process.spawn)('fuser', ['-k TERM', `-n tcp ${this.port}`], {
|
|
834
|
+
shell: true
|
|
835
|
+
});
|
|
836
|
+
debug('browser killed');
|
|
837
|
+
}
|
|
838
|
+
killBrowser() {
|
|
839
|
+
if (!this.processSpawned.pid) {
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
try {
|
|
843
|
+
this.processSpawned.kill();
|
|
844
|
+
debug('browser killed');
|
|
845
|
+
} catch (error) {
|
|
846
|
+
console.error(error);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
async killAndCommit(options, local = false) {
|
|
850
|
+
this.killBrowser();
|
|
851
|
+
await delay(this.processKillTimeout);
|
|
852
|
+
await this.stopAndCommit(options, local).catch(console.error);
|
|
853
|
+
}
|
|
854
|
+
async sanitizeProfile() {
|
|
855
|
+
const remove_dirs = [`${SEPARATOR}Default${SEPARATOR}Cache`, `${SEPARATOR}Default${SEPARATOR}Service Worker`, `${SEPARATOR}Default${SEPARATOR}Code Cache`, `${SEPARATOR}Default${SEPARATOR}GPUCache`, `${SEPARATOR}Default${SEPARATOR}Extensions`, `${SEPARATOR}Default${SEPARATOR}IndexedDB`, `${SEPARATOR}Default${SEPARATOR}GPUCache`, `${SEPARATOR}Default${SEPARATOR}DawnCache`, `${SEPARATOR}Default${SEPARATOR}fonts_config`, `${SEPARATOR}GrShaderCache`, `${SEPARATOR}ShaderCache`, `${SEPARATOR}biahpgbdmdkfgndcmfiipgcebobojjkp`, `${SEPARATOR}afalakplffnnnlkncjhbmahjfjhmlkal`, `${SEPARATOR}cffkpbalmllkdoenhmdmpbkajipdjfam`, `${SEPARATOR}Dictionaries`, `${SEPARATOR}enkheaiicpeffbfgjiklngbpkilnbkoi`, `${SEPARATOR}oofiananboodjbbmdelgdommihjbkfag`, `${SEPARATOR}SafetyTips`, `${SEPARATOR}fonts`, `${SEPARATOR}BrowserMetrics`, `${SEPARATOR}BrowserMetrics-spare.pma`];
|
|
856
|
+
const that = this;
|
|
857
|
+
await Promise.all(remove_dirs.map(d => {
|
|
858
|
+
const path_to_remove = `${that.profilePath()}${d}`;
|
|
859
|
+
return new Promise(resolve => {
|
|
860
|
+
debug('DROPPING', path_to_remove);
|
|
861
|
+
(0, _rimraf.default)(path_to_remove, {
|
|
862
|
+
maxBusyTries: 100
|
|
863
|
+
}, e => {
|
|
864
|
+
// debug('DROPPING RESULT', e);
|
|
865
|
+
resolve();
|
|
866
|
+
});
|
|
867
|
+
});
|
|
868
|
+
}));
|
|
869
|
+
}
|
|
870
|
+
async getProfileDataToUpdate() {
|
|
871
|
+
const zipPath = (0, _path.join)(this.tmpdir, `gologin_${this.profile_id}_upload.zip`);
|
|
872
|
+
const zipExists = await access(zipPath).then(() => true).catch(() => false);
|
|
873
|
+
if (zipExists) {
|
|
874
|
+
await unlink(zipPath);
|
|
875
|
+
}
|
|
876
|
+
await this.sanitizeProfile();
|
|
877
|
+
debug('profile sanitized');
|
|
878
|
+
const profilePath = this.profilePath();
|
|
879
|
+
const fileBuff = await (0, _profileArchiver.archiveProfile)(profilePath);
|
|
880
|
+
debug('PROFILE ZIP CREATED', profilePath, zipPath);
|
|
881
|
+
return fileBuff;
|
|
882
|
+
}
|
|
883
|
+
async profileExists() {
|
|
884
|
+
const profileResponse = await _requestretry.default.post(`${_common.API_URL}/browser`, {
|
|
885
|
+
headers: {
|
|
886
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
887
|
+
'User-Agent': 'gologin-api'
|
|
888
|
+
},
|
|
889
|
+
json: {}
|
|
890
|
+
});
|
|
891
|
+
if (profileResponse.statusCode !== 200) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
debug('profile is', profileResponse.body);
|
|
895
|
+
return true;
|
|
896
|
+
}
|
|
897
|
+
async getRandomFingerprint(options) {
|
|
898
|
+
let os = 'lin';
|
|
899
|
+
if (options.os) {
|
|
900
|
+
os = options.os;
|
|
901
|
+
}
|
|
902
|
+
let url = `${_common.API_URL}/browser/fingerprint?os=${os}`;
|
|
903
|
+
if (options.isM1) {
|
|
904
|
+
url += '&isM1=true';
|
|
905
|
+
}
|
|
906
|
+
const fingerprint = await _requestretry.default.get(url, {
|
|
907
|
+
headers: {
|
|
908
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
909
|
+
'User-Agent': 'gologin-api'
|
|
910
|
+
}
|
|
911
|
+
});
|
|
912
|
+
return JSON.parse(fingerprint.body);
|
|
913
|
+
}
|
|
914
|
+
async create(options) {
|
|
915
|
+
debug('createProfile', options);
|
|
916
|
+
const fingerprint = await this.getRandomFingerprint(options);
|
|
917
|
+
debug('fingerprint=', fingerprint);
|
|
918
|
+
if (fingerprint.statusCode === 500) {
|
|
919
|
+
throw new Error('no valid random fingerprint check os param');
|
|
920
|
+
}
|
|
921
|
+
if (fingerprint.statusCode === 401) {
|
|
922
|
+
throw new Error('invalid token');
|
|
923
|
+
}
|
|
924
|
+
const {
|
|
925
|
+
navigator,
|
|
926
|
+
fonts,
|
|
927
|
+
webGLMetadata,
|
|
928
|
+
webRTC
|
|
929
|
+
} = fingerprint;
|
|
930
|
+
let deviceMemory = navigator.deviceMemory || 2;
|
|
931
|
+
if (deviceMemory < 1) {
|
|
932
|
+
deviceMemory = 1;
|
|
933
|
+
}
|
|
934
|
+
navigator.deviceMemory = deviceMemory * 1024;
|
|
935
|
+
webGLMetadata.mode = webGLMetadata.mode === 'noise' ? 'mask' : 'off';
|
|
936
|
+
const json = {
|
|
937
|
+
...fingerprint,
|
|
938
|
+
navigator,
|
|
939
|
+
webGLMetadata,
|
|
940
|
+
browserType: 'chrome',
|
|
941
|
+
name: 'default_name',
|
|
942
|
+
notes: 'auto generated',
|
|
943
|
+
fonts: {
|
|
944
|
+
families: fonts
|
|
945
|
+
},
|
|
946
|
+
webRTC: {
|
|
947
|
+
...webRTC,
|
|
948
|
+
mode: 'alerted'
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
const user_agent = options.navigator?.userAgent;
|
|
952
|
+
const orig_user_agent = json.navigator.userAgent;
|
|
953
|
+
Object.keys(options).forEach(key => {
|
|
954
|
+
if (typeof json[key] === 'object') {
|
|
955
|
+
json[key] = {
|
|
956
|
+
...json[key],
|
|
957
|
+
...options[key]
|
|
958
|
+
};
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
json[key] = options[key];
|
|
962
|
+
});
|
|
963
|
+
if (user_agent === 'random') {
|
|
964
|
+
json.navigator.userAgent = orig_user_agent;
|
|
965
|
+
}
|
|
966
|
+
const response = await _requestretry.default.post(`${_common.API_URL}/browser`, {
|
|
967
|
+
headers: {
|
|
968
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
969
|
+
'User-Agent': 'gologin-api'
|
|
970
|
+
},
|
|
971
|
+
json
|
|
972
|
+
});
|
|
973
|
+
if (response.statusCode === 400) {
|
|
974
|
+
throw new Error(`gologin failed account creation with status code, ${response.statusCode} DATA ${JSON.stringify(response.body.message)}`);
|
|
975
|
+
}
|
|
976
|
+
if (response.statusCode === 500) {
|
|
977
|
+
throw new Error(`gologin failed account creation with status code, ${response.statusCode}`);
|
|
978
|
+
}
|
|
979
|
+
debug(JSON.stringify(response.body));
|
|
980
|
+
return response.body.id;
|
|
981
|
+
}
|
|
982
|
+
async createCustom(options) {
|
|
983
|
+
debug('createCustomProfile', options);
|
|
984
|
+
const response = await _requestretry.default.post(`${_common.API_URL}/browser/custom`, {
|
|
985
|
+
headers: {
|
|
986
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
987
|
+
'User-Agent': 'gologin-api'
|
|
988
|
+
},
|
|
989
|
+
json: options
|
|
990
|
+
});
|
|
991
|
+
if (response.statusCode === 400) {
|
|
992
|
+
throw new Error(`gologin failed account creation with status code, ${response.statusCode} DATA ${JSON.stringify(response.body.message)}`);
|
|
993
|
+
}
|
|
994
|
+
if (response.statusCode === 500) {
|
|
995
|
+
throw new Error(`gologin failed account creation with status code, ${response.statusCode}`);
|
|
996
|
+
}
|
|
997
|
+
debug(JSON.stringify(response));
|
|
998
|
+
return response.body.id;
|
|
999
|
+
}
|
|
1000
|
+
async quickCreateProfile(name = '') {
|
|
1001
|
+
const osInfo = await (0, _common.getOsAdvanced)();
|
|
1002
|
+
const {
|
|
1003
|
+
os,
|
|
1004
|
+
osSpec
|
|
1005
|
+
} = osInfo;
|
|
1006
|
+
const resultName = name || 'api-generated';
|
|
1007
|
+
return _requestretry.default.post(`${_common.API_URL}/browser/quick`, {
|
|
1008
|
+
headers: {
|
|
1009
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
1010
|
+
'User-Agent': 'gologin-api'
|
|
1011
|
+
},
|
|
1012
|
+
json: {
|
|
1013
|
+
os,
|
|
1014
|
+
osSpec,
|
|
1015
|
+
name: resultName
|
|
1016
|
+
}
|
|
1017
|
+
}).then(res => res.body);
|
|
1018
|
+
}
|
|
1019
|
+
async delete(pid) {
|
|
1020
|
+
const profile_id = pid || this.profile_id;
|
|
1021
|
+
await _requestretry.default.delete(`${_common.API_URL}/browser/${profile_id}`, {
|
|
1022
|
+
headers: {
|
|
1023
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
1024
|
+
'User-Agent': 'gologin-api'
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
async update(options) {
|
|
1029
|
+
this.profile_id = options.id;
|
|
1030
|
+
const profile = await this.getProfile();
|
|
1031
|
+
if (options.navigator) {
|
|
1032
|
+
Object.keys(options.navigator).map(e => {
|
|
1033
|
+
profile.navigator[e] = options.navigator[e];
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
Object.keys(options).filter(el => el !== 'navigator').forEach(el => {
|
|
1037
|
+
profile[el] = options[el];
|
|
1038
|
+
});
|
|
1039
|
+
debug('update profile', profile);
|
|
1040
|
+
const response = await _requestretry.default.put(`${_common.API_URL}/browser/${options.id}`, {
|
|
1041
|
+
json: profile,
|
|
1042
|
+
headers: {
|
|
1043
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
1044
|
+
'User-Agent': 'gologin-api'
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
debug('response', JSON.stringify(response.body));
|
|
1048
|
+
return response.body;
|
|
1049
|
+
}
|
|
1050
|
+
setActive(is_active) {
|
|
1051
|
+
this.is_active = is_active;
|
|
1052
|
+
}
|
|
1053
|
+
getGeolocationParams(profileGeolocationParams, tzGeolocationParams) {
|
|
1054
|
+
if (profileGeolocationParams.fillBasedOnIp) {
|
|
1055
|
+
return {
|
|
1056
|
+
mode: profileGeolocationParams.mode,
|
|
1057
|
+
latitude: Number(tzGeolocationParams.latitude),
|
|
1058
|
+
longitude: Number(tzGeolocationParams.longitude),
|
|
1059
|
+
accuracy: Number(tzGeolocationParams.accuracy)
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
return {
|
|
1063
|
+
mode: profileGeolocationParams.mode,
|
|
1064
|
+
latitude: profileGeolocationParams.latitude,
|
|
1065
|
+
longitude: profileGeolocationParams.longitude,
|
|
1066
|
+
accuracy: profileGeolocationParams.accuracy
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
getViewPort() {
|
|
1070
|
+
return {
|
|
1071
|
+
...this.resolution
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
async postCookies(profileId, cookies) {
|
|
1075
|
+
const formattedCookies = cookies.map(cookie => {
|
|
1076
|
+
if (!['no_restriction', 'lax', 'strict', 'unspecified'].includes(cookie.sameSite)) {
|
|
1077
|
+
cookie.sameSite = 'unspecified';
|
|
1078
|
+
}
|
|
1079
|
+
return cookie;
|
|
1080
|
+
});
|
|
1081
|
+
const response = await (0, _browserUserDataManager.uploadCookies)({
|
|
1082
|
+
profileId,
|
|
1083
|
+
cookies: formattedCookies,
|
|
1084
|
+
API_BASE_URL: _common.API_URL,
|
|
1085
|
+
ACCESS_TOKEN: this.access_token
|
|
1086
|
+
});
|
|
1087
|
+
if (response.statusCode === 200) {
|
|
1088
|
+
return response.body;
|
|
1089
|
+
}
|
|
1090
|
+
return {
|
|
1091
|
+
status: 'failure',
|
|
1092
|
+
status_code: response.statusCode,
|
|
1093
|
+
body: response.body
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
async getCookies(profileId) {
|
|
1097
|
+
const response = await (0, _browserUserDataManager.downloadCookies)({
|
|
1098
|
+
profileId,
|
|
1099
|
+
API_BASE_URL: _common.API_URL,
|
|
1100
|
+
ACCESS_TOKEN: this.access_token
|
|
1101
|
+
});
|
|
1102
|
+
return response.body;
|
|
1103
|
+
}
|
|
1104
|
+
async writeCookiesToFile() {
|
|
1105
|
+
const cookies = await this.getCookies(this.profile_id);
|
|
1106
|
+
const resultCookies = cookies.map(el => ({
|
|
1107
|
+
...el,
|
|
1108
|
+
value: Buffer.from(el.value)
|
|
1109
|
+
}));
|
|
1110
|
+
let db;
|
|
1111
|
+
try {
|
|
1112
|
+
db = await (0, _cookiesManager.getDB)(this.cookiesFilePath, false);
|
|
1113
|
+
if (resultCookies.length) {
|
|
1114
|
+
const chunckInsertValues = (0, _cookiesManager.getChunckedInsertValues)(resultCookies);
|
|
1115
|
+
for (const [query, queryParams] of chunckInsertValues) {
|
|
1116
|
+
const insertStmt = await db.prepare(query);
|
|
1117
|
+
await insertStmt.run(queryParams);
|
|
1118
|
+
await insertStmt.finalize();
|
|
1119
|
+
}
|
|
1120
|
+
} else {
|
|
1121
|
+
const query = 'delete from cookies';
|
|
1122
|
+
const insertStmt = await db.prepare(query);
|
|
1123
|
+
await insertStmt.run();
|
|
1124
|
+
await insertStmt.finalize();
|
|
1125
|
+
}
|
|
1126
|
+
} catch (error) {
|
|
1127
|
+
console.log(error.message);
|
|
1128
|
+
} finally {
|
|
1129
|
+
db && (await db.close());
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
async uploadProfileCookiesToServer() {
|
|
1133
|
+
const cookies = await (0, _cookiesManager.loadCookiesFromFile)(this.cookiesFilePath);
|
|
1134
|
+
if (!cookies.length) {
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
return this.postCookies(this.profile_id, cookies);
|
|
1138
|
+
}
|
|
1139
|
+
async saveBookmarksToDb() {
|
|
1140
|
+
const bookmarksData = await (0, _utils.getCurrentProfileBookmarks)(this.bookmarksFilePath);
|
|
1141
|
+
const bookmarks = bookmarksData.roots || {};
|
|
1142
|
+
await (0, _browserApi.updateProfileBookmarks)([this.profile_id], this.access_token, bookmarks);
|
|
1143
|
+
}
|
|
1144
|
+
async start() {
|
|
1145
|
+
if (this.is_remote) {
|
|
1146
|
+
return this.startRemote();
|
|
1147
|
+
}
|
|
1148
|
+
if (!this.executablePath) {
|
|
1149
|
+
await this.checkBrowser();
|
|
1150
|
+
}
|
|
1151
|
+
const ORBITA_BROWSER = this.executablePath || this.browserChecker.getOrbitaPath;
|
|
1152
|
+
const orbitaBrowserExists = await access(ORBITA_BROWSER).then(() => true).catch(() => false);
|
|
1153
|
+
if (!orbitaBrowserExists) {
|
|
1154
|
+
throw new Error(`Orbita browser is not exists on path ${ORBITA_BROWSER}, check executablePath param`);
|
|
1155
|
+
}
|
|
1156
|
+
await this.createStartup();
|
|
1157
|
+
// await this.createBrowserExtension();
|
|
1158
|
+
const wsUrl = await this.spawnBrowser();
|
|
1159
|
+
this.setActive(true);
|
|
1160
|
+
return {
|
|
1161
|
+
status: 'success',
|
|
1162
|
+
wsUrl
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
async startLocal() {
|
|
1166
|
+
await this.createStartup(true);
|
|
1167
|
+
// await this.createBrowserExtension();
|
|
1168
|
+
const wsUrl = await this.spawnBrowser();
|
|
1169
|
+
this.setActive(true);
|
|
1170
|
+
return {
|
|
1171
|
+
status: 'success',
|
|
1172
|
+
wsUrl
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
async stop() {
|
|
1176
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
1177
|
+
if (this.is_remote) {
|
|
1178
|
+
return this.stopRemote();
|
|
1179
|
+
}
|
|
1180
|
+
await this.stopAndCommit({
|
|
1181
|
+
posting: true
|
|
1182
|
+
}, false);
|
|
1183
|
+
}
|
|
1184
|
+
async stopLocal(options) {
|
|
1185
|
+
const opts = options || {
|
|
1186
|
+
posting: false
|
|
1187
|
+
};
|
|
1188
|
+
await this.stopAndCommit(opts, true);
|
|
1189
|
+
}
|
|
1190
|
+
async waitDebuggingUrl(delay_ms, try_count = 0, remoteOrbitaUrl) {
|
|
1191
|
+
await delay(delay_ms);
|
|
1192
|
+
const url = `${remoteOrbitaUrl}/json/version`;
|
|
1193
|
+
console.log('try_count=', try_count, 'url=', url);
|
|
1194
|
+
const response = await _requestretry.default.get(url);
|
|
1195
|
+
let wsUrl = '';
|
|
1196
|
+
console.log('response', response.body);
|
|
1197
|
+
if (!response.body) {
|
|
1198
|
+
return wsUrl;
|
|
1199
|
+
}
|
|
1200
|
+
try {
|
|
1201
|
+
const parsedBody = JSON.parse(response.body);
|
|
1202
|
+
wsUrl = parsedBody.webSocketDebuggerUrl;
|
|
1203
|
+
} catch (e) {
|
|
1204
|
+
if (try_count < 3) {
|
|
1205
|
+
return this.waitDebuggingUrl(delay_ms, try_count + 1, remoteOrbitaUrl);
|
|
1206
|
+
}
|
|
1207
|
+
return {
|
|
1208
|
+
status: 'failure',
|
|
1209
|
+
wsUrl,
|
|
1210
|
+
message: 'Check proxy settings',
|
|
1211
|
+
'profile_id': this.profile_id
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
const remoteOrbitaUrlWithoutProtocol = remoteOrbitaUrl.replace('https://', '');
|
|
1215
|
+
wsUrl = wsUrl.replace('ws://', 'wss://').replace('127.0.0.1', remoteOrbitaUrlWithoutProtocol);
|
|
1216
|
+
return wsUrl;
|
|
1217
|
+
}
|
|
1218
|
+
async startRemote(delay_ms = 10000) {
|
|
1219
|
+
debug(`startRemote ${this.profile_id}`);
|
|
1220
|
+
|
|
1221
|
+
/*
|
|
1222
|
+
if (profileResponse.statusCode !== 202) {
|
|
1223
|
+
return {'status': 'failure', 'code': profileResponse.statusCode};
|
|
1224
|
+
}
|
|
1225
|
+
*/
|
|
1226
|
+
|
|
1227
|
+
const profile = await this.getProfile();
|
|
1228
|
+
const profileResponse = await _requestretry.default.post(`${_common.API_URL}/browser/${this.profile_id}/web`, {
|
|
1229
|
+
headers: {
|
|
1230
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
1231
|
+
'User-Agent': 'gologin-api'
|
|
1232
|
+
},
|
|
1233
|
+
json: {
|
|
1234
|
+
isNewCloudBrowser: this.isNewCloudBrowser,
|
|
1235
|
+
isHeadless: this.isCloudHeadless
|
|
1236
|
+
}
|
|
1237
|
+
}).catch(() => null);
|
|
1238
|
+
if (!profileResponse) {
|
|
1239
|
+
throw new Error('invalid request');
|
|
1240
|
+
}
|
|
1241
|
+
const {
|
|
1242
|
+
body,
|
|
1243
|
+
statusCode
|
|
1244
|
+
} = profileResponse;
|
|
1245
|
+
debug('profileResponse', statusCode, body);
|
|
1246
|
+
if (profileResponse.statusCode === 401) {
|
|
1247
|
+
throw new Error('invalid token');
|
|
1248
|
+
}
|
|
1249
|
+
if (body.status === 'profileStatuses.pending') {
|
|
1250
|
+
return {
|
|
1251
|
+
status: 'pending',
|
|
1252
|
+
message: 'remote browser is being prepared, please try in 1 minute.'
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
let remoteOrbitaUrl = `https://${this.profile_id}.orbita.gologin.com`;
|
|
1256
|
+
if (this.isNewCloudBrowser) {
|
|
1257
|
+
if (!profileResponse.body.remoteOrbitaUrl) {
|
|
1258
|
+
throw new Error('Couldn\' start the remote browser');
|
|
1259
|
+
}
|
|
1260
|
+
remoteOrbitaUrl = profileResponse.body.remoteOrbitaUrl;
|
|
1261
|
+
}
|
|
1262
|
+
const {
|
|
1263
|
+
navigator = {},
|
|
1264
|
+
fonts,
|
|
1265
|
+
os: profileOs
|
|
1266
|
+
} = profile;
|
|
1267
|
+
this.fontsMasking = fonts?.enableMasking;
|
|
1268
|
+
this.profileOs = profileOs;
|
|
1269
|
+
this.differentOs = profileOs !== 'android' && (OS_PLATFORM === 'win32' && profileOs !== 'win' || OS_PLATFORM === 'darwin' && profileOs !== 'mac' || OS_PLATFORM === 'linux' && profileOs !== 'lin');
|
|
1270
|
+
const {
|
|
1271
|
+
resolution = '1920x1080',
|
|
1272
|
+
language = 'en-US,en;q=0.9'
|
|
1273
|
+
} = navigator;
|
|
1274
|
+
this.language = language;
|
|
1275
|
+
const [screenWidth, screenHeight] = resolution.split('x');
|
|
1276
|
+
this.resolution = {
|
|
1277
|
+
width: parseInt(screenWidth, 10),
|
|
1278
|
+
height: parseInt(screenHeight, 10)
|
|
1279
|
+
};
|
|
1280
|
+
const wsUrl = await this.waitDebuggingUrl(delay_ms, 0, remoteOrbitaUrl);
|
|
1281
|
+
if (wsUrl !== '') {
|
|
1282
|
+
return {
|
|
1283
|
+
status: 'success',
|
|
1284
|
+
wsUrl
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
return {
|
|
1288
|
+
status: 'failure',
|
|
1289
|
+
message: body
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
async stopRemote() {
|
|
1293
|
+
debug(`stopRemote ${this.profile_id}`);
|
|
1294
|
+
const profileResponse = await _requestretry.default.delete(`${_common.API_URL}/browser/${this.profile_id}/web?isNewCloudBrowser=${this.isNewCloudBrowser}`, {
|
|
1295
|
+
headers: {
|
|
1296
|
+
'Authorization': `Bearer ${this.access_token}`,
|
|
1297
|
+
'User-Agent': 'gologin-api'
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
console.log(`stopRemote ${profileResponse.body}`);
|
|
1301
|
+
if (profileResponse.body) {
|
|
1302
|
+
return JSON.parse(profileResponse.body);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
getAvailableFonts() {
|
|
1306
|
+
return _fonts.fontsCollection.filter(elem => elem.fileNames).map(elem => elem.name);
|
|
1307
|
+
}
|
|
1308
|
+
async changeProfileResolution(resolution) {
|
|
1309
|
+
return (0, _browserApi.updateProfileResolution)(this.profile_id, this.access_token, resolution);
|
|
1310
|
+
}
|
|
1311
|
+
async changeProfileUserAgent(userAgent) {
|
|
1312
|
+
return (0, _browserApi.updateProfileUserAgent)(this.profile_id, this.access_token, userAgent);
|
|
1313
|
+
}
|
|
1314
|
+
async changeProfileProxy(proxyData) {
|
|
1315
|
+
return (0, _browserApi.updateProfileProxy)(this.profile_id, this.access_token, proxyData);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
exports.GoLogin = GoLogin;
|
|
1319
|
+
var _default = exports.default = GoLogin;
|