gologin 1.0.31 → 1.0.32
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/gologin.js +121 -68
- package/package.json +3 -3
package/gologin.js
CHANGED
|
@@ -5,6 +5,7 @@ const fs = require('fs');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const util = require('util');
|
|
7
7
|
const rimraf = util.promisify(require('rimraf'));
|
|
8
|
+
const { access, unlink, writeFile, readFile } = require('fs').promises;
|
|
8
9
|
const exec = util.promisify(require('child_process').exec);
|
|
9
10
|
const { spawn, execFile } = require('child_process');
|
|
10
11
|
const FormData = require('form-data');
|
|
@@ -12,7 +13,7 @@ const ProxyAgent = require('simple-proxy-agent');
|
|
|
12
13
|
const decompress = require('decompress');
|
|
13
14
|
const decompressUnzip = require('decompress-unzip');
|
|
14
15
|
const path = require('path');
|
|
15
|
-
const
|
|
16
|
+
const zipdir = require('zip-dir');
|
|
16
17
|
|
|
17
18
|
const BrowserChecker = require('./browser-checker');
|
|
18
19
|
const { BrowserUserDataManager } = require('./browser-user-data-manager');
|
|
@@ -54,7 +55,7 @@ class GoLogin {
|
|
|
54
55
|
this.tmpdir = options.tmpdir;
|
|
55
56
|
if (!fs.existsSync(this.tmpdir)) {
|
|
56
57
|
debug('making tmpdir', this.tmpdir);
|
|
57
|
-
|
|
58
|
+
fs.mkdirSync(this.tmpdir, { recursive: true })
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -127,7 +128,7 @@ class GoLogin {
|
|
|
127
128
|
throw new Error(`Gologin /browser/${id} response error ${profileResponse.statusCode} INVALID TOKEN OR PROFILE NOT FOUND`);
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
if(profileResponse.statusCode
|
|
131
|
+
if (profileResponse.statusCode === 401) {
|
|
131
132
|
throw new Error("invalid token");
|
|
132
133
|
}
|
|
133
134
|
|
|
@@ -135,12 +136,13 @@ class GoLogin {
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
async emptyProfile() {
|
|
138
|
-
|
|
139
|
+
return readFile(path.resolve(__dirname, 'gologin_zeroprofile.b64')).then(res => res.toString());
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
async getProfileS3(s3path) {
|
|
142
143
|
const token = this.access_token;
|
|
143
144
|
debug('getProfileS3 token=', token, 'profile=', this.profile_id, 's3path=', s3path);
|
|
145
|
+
|
|
144
146
|
if (s3path) { //загрузка профиля из публичного бакета s3 быстрее
|
|
145
147
|
const s3url = `https://gprofiles.gologin.com/${s3path}`.replace(/\s+/mg, '+');
|
|
146
148
|
debug('loading profile from public s3 bucket, url=', s3url);
|
|
@@ -151,6 +153,7 @@ class GoLogin {
|
|
|
151
153
|
debug(`Gologin S3 BUCKET ${s3url} response error ${profileResponse.statusCode} - use empty`);
|
|
152
154
|
return '';
|
|
153
155
|
}
|
|
156
|
+
|
|
154
157
|
return Buffer.from(profileResponse.body);
|
|
155
158
|
}
|
|
156
159
|
|
|
@@ -161,15 +164,33 @@ class GoLogin {
|
|
|
161
164
|
},
|
|
162
165
|
encoding: null
|
|
163
166
|
});
|
|
167
|
+
|
|
164
168
|
if (profileResponse.statusCode !== 200) {
|
|
165
169
|
debug(`Gologin /browser/${this.profile_id} response error ${profileResponse.statusCode} - use empty`);
|
|
166
170
|
return '';
|
|
167
171
|
}
|
|
172
|
+
|
|
168
173
|
return Buffer.from(profileResponse.body);
|
|
169
174
|
}
|
|
170
175
|
|
|
171
176
|
async postFile(fileName, fileBody) {
|
|
172
177
|
debug('POSTING FILE', fileBody.length);
|
|
178
|
+
debug('Getting signed URL for S3');
|
|
179
|
+
const apiUrl = `${API_URL}/browser/${this.profile_id}/storage-signature`;
|
|
180
|
+
|
|
181
|
+
const signedUrl = await requests.get(apiUrl, {
|
|
182
|
+
headers: {
|
|
183
|
+
Authorization: `Bearer ${this.access_token}`,
|
|
184
|
+
'user-agent': 'gologin-api',
|
|
185
|
+
},
|
|
186
|
+
maxAttempts: 3,
|
|
187
|
+
retryDelay: 2000,
|
|
188
|
+
timeout: 10 * 1000,
|
|
189
|
+
fullResponse: false,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const [uploadedProfileUrl] = signedUrl.split('?');
|
|
193
|
+
|
|
173
194
|
const fd = new FormData();
|
|
174
195
|
const boundary = fd.getBoundary();
|
|
175
196
|
const body = Buffer.concat([
|
|
@@ -186,26 +207,44 @@ class GoLogin {
|
|
|
186
207
|
Buffer.from('--'),
|
|
187
208
|
Buffer.from('\r\n')
|
|
188
209
|
]);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
210
|
+
|
|
211
|
+
console.log('Uploading profile by signed URL to S3');
|
|
212
|
+
const bodyBufferBiteLength = Buffer.byteLength(body);
|
|
213
|
+
console.log('BUFFER SIZE', bodyBufferBiteLength);
|
|
214
|
+
|
|
215
|
+
await requests.put(signedUrl, {
|
|
216
|
+
headers: {
|
|
217
|
+
'Content-Type': 'application/zip',
|
|
218
|
+
'Content-Length': bodyBufferBiteLength,
|
|
219
|
+
},
|
|
220
|
+
body,
|
|
221
|
+
maxBodyLength: Infinity,
|
|
222
|
+
maxContentLength: Infinity,
|
|
223
|
+
maxAttempts: 3,
|
|
224
|
+
retryDelay: 2000,
|
|
225
|
+
timeout: 30 * 1000,
|
|
226
|
+
fullResponse: false,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const uploadedProfileMetadata = await requests.head(uploadedProfileUrl, {
|
|
230
|
+
maxAttempts: 3,
|
|
231
|
+
retryDelay: 2000,
|
|
232
|
+
timeout: 10 * 1000,
|
|
233
|
+
fullResponse: true,
|
|
203
234
|
});
|
|
235
|
+
|
|
236
|
+
const uploadedFileLength = +uploadedProfileMetadata.headers['content-length'];
|
|
237
|
+
if (uploadedFileLength !== bodyBufferBiteLength) {
|
|
238
|
+
console.log('Uploaded file is incorrect. Retry with China File size:', uploadedFileLength);
|
|
239
|
+
throw new Error('Uploaded file is incorrect. Retry with China File size: ' + uploadedFileLength);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log('Profile has been uploaded to S3 successfully');
|
|
204
243
|
}
|
|
205
244
|
|
|
206
245
|
async emptyProfileFolder() {
|
|
207
246
|
debug('get emptyProfileFolder');
|
|
208
|
-
const profile =
|
|
247
|
+
const profile = await readFile(path.resolve(__dirname, 'gologin_zeroprofile.zip'));
|
|
209
248
|
debug('emptyProfileFolder LENGTH ::', profile.length);
|
|
210
249
|
return profile;
|
|
211
250
|
}
|
|
@@ -246,9 +285,8 @@ class GoLogin {
|
|
|
246
285
|
.then(() => {
|
|
247
286
|
debug('extraction done');
|
|
248
287
|
debug('create uid.json');
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return extPath;
|
|
288
|
+
return writeFile(path.join(extPath, 'uid.json'), JSON.stringify({ uid: that.profile_id }, null, 2))
|
|
289
|
+
.then(() => extPath);
|
|
252
290
|
})
|
|
253
291
|
.catch(async (e) => {
|
|
254
292
|
debug('orbita extension error', e);
|
|
@@ -299,7 +337,8 @@ class GoLogin {
|
|
|
299
337
|
height: parseInt(screenHeight, 10),
|
|
300
338
|
};
|
|
301
339
|
|
|
302
|
-
|
|
340
|
+
const profileZipExists = await access(this.profile_zip_path).then(() => true).catch(() => false);
|
|
341
|
+
if (!(local && profileZipExists)) {
|
|
303
342
|
try {
|
|
304
343
|
profile_folder = await this.getProfileS3(_.get(profile, 's3Path', ''));
|
|
305
344
|
}
|
|
@@ -310,8 +349,8 @@ class GoLogin {
|
|
|
310
349
|
if (!profile_folder.length) {
|
|
311
350
|
profile_folder = await this.emptyProfileFolder();
|
|
312
351
|
}
|
|
313
|
-
|
|
314
|
-
|
|
352
|
+
|
|
353
|
+
await writeFile(this.profile_zip_path, profile_folder);
|
|
315
354
|
|
|
316
355
|
debug('PROFILE LENGTH', profile_folder.length);
|
|
317
356
|
} else {
|
|
@@ -323,20 +362,23 @@ class GoLogin {
|
|
|
323
362
|
await this.extractProfile(profilePath, this.profile_zip_path);
|
|
324
363
|
debug('extraction done');
|
|
325
364
|
|
|
326
|
-
|
|
365
|
+
const singletonLockPath = path.join(profilePath, 'SingletonLock');
|
|
366
|
+
const singletonLockExists = await access(singletonLockPath).then(() => true).catch(() => false);
|
|
367
|
+
if (singletonLockExists) {
|
|
327
368
|
debug('removing SingletonLock');
|
|
328
|
-
|
|
369
|
+
await unlink(singletonLockPath);
|
|
329
370
|
debug('SingletonLock removed');
|
|
330
371
|
}
|
|
331
372
|
|
|
332
373
|
const pref_file_name = path.join(profilePath, 'Default', 'Preferences');
|
|
333
374
|
debug('reading', pref_file_name);
|
|
334
375
|
|
|
335
|
-
|
|
376
|
+
const prefFileExists = await access(pref_file_name).then(() => true).catch(() => false);
|
|
377
|
+
if (!prefFileExists) {
|
|
336
378
|
debug('Preferences file not exists waiting', pref_file_name);
|
|
337
379
|
}
|
|
338
380
|
|
|
339
|
-
const preferences_raw =
|
|
381
|
+
const preferences_raw = await readFile(pref_file_name);
|
|
340
382
|
let preferences = JSON.parse(preferences_raw.toString());
|
|
341
383
|
let proxy = _.get(profile, 'proxy');
|
|
342
384
|
let name = _.get(profile, 'name');
|
|
@@ -436,7 +478,7 @@ class GoLogin {
|
|
|
436
478
|
await BrowserUserDataManager.composeFonts(families, profilePath, this.differentOs);
|
|
437
479
|
}
|
|
438
480
|
|
|
439
|
-
|
|
481
|
+
await writeFile(path.join(profilePath, 'Default', 'Preferences'), JSON.stringify(_.merge(preferences, {
|
|
440
482
|
gologin
|
|
441
483
|
})));
|
|
442
484
|
|
|
@@ -450,12 +492,14 @@ class GoLogin {
|
|
|
450
492
|
|
|
451
493
|
async commitProfile() {
|
|
452
494
|
const data = await this.getProfileDataToUpdate();
|
|
495
|
+
|
|
453
496
|
debug('begin updating', data.length);
|
|
454
497
|
if (!data.length) {
|
|
455
498
|
debug('WARN: profile zip data empty - SKIPPING PROFILE COMMIT');
|
|
456
499
|
|
|
457
500
|
return;
|
|
458
501
|
}
|
|
502
|
+
|
|
459
503
|
try {
|
|
460
504
|
debug('Patching profile');
|
|
461
505
|
await this.postFile('profile', data);
|
|
@@ -463,6 +507,7 @@ class GoLogin {
|
|
|
463
507
|
catch (e) {
|
|
464
508
|
debug('CANNOT COMMIT PROFILE', e);
|
|
465
509
|
}
|
|
510
|
+
|
|
466
511
|
debug('COMMIT COMPLETED');
|
|
467
512
|
}
|
|
468
513
|
|
|
@@ -482,16 +527,16 @@ class GoLogin {
|
|
|
482
527
|
|
|
483
528
|
async checkPortAvailable(port) {
|
|
484
529
|
debug('CHECKING PORT AVAILABLE', port);
|
|
530
|
+
|
|
485
531
|
try {
|
|
486
532
|
const { stdout, stderr } = await exec(`lsof -i:${port}`);
|
|
487
|
-
if (
|
|
488
|
-
stdout && stdout.match(/LISTEN/gmi)
|
|
489
|
-
) {
|
|
533
|
+
if (stdout && stdout.match(/LISTEN/gmi)) {
|
|
490
534
|
debug(`PORT ${port} IS BUSY`)
|
|
491
535
|
return false;
|
|
492
536
|
}
|
|
493
|
-
} catch (e) {
|
|
537
|
+
} catch (e) {}
|
|
494
538
|
debug(`PORT ${port} IS OPEN`);
|
|
539
|
+
|
|
495
540
|
return true;
|
|
496
541
|
}
|
|
497
542
|
|
|
@@ -507,7 +552,7 @@ class GoLogin {
|
|
|
507
552
|
|
|
508
553
|
async getTimeZone(proxy) {
|
|
509
554
|
debug('getting timeZone proxy=', proxy);
|
|
510
|
-
if(this.timezone){
|
|
555
|
+
if (this.timezone) {
|
|
511
556
|
debug('getTimeZone from options', this.timezone);
|
|
512
557
|
this._tz = this.timezone;
|
|
513
558
|
return this._tz.timezone;
|
|
@@ -604,7 +649,7 @@ class GoLogin {
|
|
|
604
649
|
|
|
605
650
|
async spawnBrowser() {
|
|
606
651
|
let remote_debugging_port = this.remote_debugging_port;
|
|
607
|
-
if(!remote_debugging_port){
|
|
652
|
+
if (!remote_debugging_port) {
|
|
608
653
|
remote_debugging_port = await this.getRandomPort();
|
|
609
654
|
}
|
|
610
655
|
|
|
@@ -706,7 +751,9 @@ class GoLogin {
|
|
|
706
751
|
if (this.is_stopping) {
|
|
707
752
|
return true;
|
|
708
753
|
}
|
|
709
|
-
const is_posting = options.
|
|
754
|
+
const is_posting = options.posting ||
|
|
755
|
+
options.postings || // backward compability
|
|
756
|
+
false;
|
|
710
757
|
|
|
711
758
|
if (this.uploadCookiesToServer) {
|
|
712
759
|
await this.uploadProfileCookiesToServer();
|
|
@@ -782,34 +829,39 @@ class GoLogin {
|
|
|
782
829
|
|
|
783
830
|
async getProfileDataToUpdate() {
|
|
784
831
|
const zipPath = path.join(this.tmpdir, `gologin_${this.profile_id}_upload.zip`);
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
catch (e) {
|
|
832
|
+
const zipExists = await access(zipPath).then(() => true).catch(() => false);
|
|
833
|
+
if (zipExists) {
|
|
834
|
+
await unlink(zipPath);
|
|
789
835
|
}
|
|
836
|
+
|
|
790
837
|
await this.sanitizeProfile();
|
|
791
838
|
debug('profile sanitized');
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
839
|
+
|
|
840
|
+
const profilePath = this.profilePath();
|
|
841
|
+
await new Promise((resolve, reject) => zipdir(profilePath,
|
|
842
|
+
{
|
|
843
|
+
saveTo: zipPath,
|
|
844
|
+
filter: (path) => !/RunningChromeVersion/.test(path),
|
|
845
|
+
}, (err, buffer) => {
|
|
846
|
+
if (err) {
|
|
847
|
+
reject(err);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
resolve(buffer);
|
|
852
|
+
})
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
debug('PROFILE ZIP CREATED', profilePath, zipPath);
|
|
856
|
+
|
|
857
|
+
let data = '';
|
|
805
858
|
try {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
catch (e) {
|
|
859
|
+
data = await readFile(zipPath);
|
|
860
|
+
} catch (e) {
|
|
810
861
|
debug('saveprofile error', e);
|
|
811
|
-
return '';
|
|
812
862
|
}
|
|
863
|
+
|
|
864
|
+
return data;
|
|
813
865
|
}
|
|
814
866
|
|
|
815
867
|
async profileExists() {
|
|
@@ -853,11 +905,11 @@ class GoLogin {
|
|
|
853
905
|
const fingerprint = await this.getRandomFingerprint(options);
|
|
854
906
|
debug("fingerprint=", fingerprint)
|
|
855
907
|
|
|
856
|
-
if(fingerprint.statusCode
|
|
908
|
+
if (fingerprint.statusCode === 500) {
|
|
857
909
|
throw new Error("no valid random fingerprint check os param");
|
|
858
910
|
}
|
|
859
911
|
|
|
860
|
-
if(fingerprint.statusCode
|
|
912
|
+
if (fingerprint.statusCode === 401) {
|
|
861
913
|
throw new Error("invalid token");
|
|
862
914
|
}
|
|
863
915
|
|
|
@@ -887,7 +939,7 @@ class GoLogin {
|
|
|
887
939
|
let user_agent = options.navigator?.userAgent;
|
|
888
940
|
let orig_user_agent = json.navigator.userAgent;
|
|
889
941
|
Object.keys(options).map((e)=>{ json[e] = options[e] });
|
|
890
|
-
if(user_agent
|
|
942
|
+
if (user_agent === 'random') {
|
|
891
943
|
json.navigator.userAgent = orig_user_agent;
|
|
892
944
|
}
|
|
893
945
|
// console.log('profileOptions', json);
|
|
@@ -900,11 +952,11 @@ class GoLogin {
|
|
|
900
952
|
json,
|
|
901
953
|
});
|
|
902
954
|
|
|
903
|
-
if(response.body.statusCode
|
|
955
|
+
if (response.body.statusCode === 400) {
|
|
904
956
|
throw new Error(`gologin failed account creation with status code, ${data.statusCode} DATA ${JSON.stringify(response.body.message)}`);
|
|
905
957
|
}
|
|
906
958
|
|
|
907
|
-
if(response.body.statusCode
|
|
959
|
+
if (response.body.statusCode === 500) {
|
|
908
960
|
throw new Error(`gologin failed account creation with status code, ${data.statusCode}`);
|
|
909
961
|
}
|
|
910
962
|
debug(JSON.stringify(response.body));
|
|
@@ -1045,7 +1097,8 @@ class GoLogin {
|
|
|
1045
1097
|
|
|
1046
1098
|
const ORBITA_BROWSER = this.executablePath || this.browserChecker.getOrbitaPath;
|
|
1047
1099
|
|
|
1048
|
-
|
|
1100
|
+
const orbitaBrowserExists = await access(ORBITA_BROWSER).then(() => true).catch(() => false);
|
|
1101
|
+
if (!orbitaBrowserExists) {
|
|
1049
1102
|
throw new Error(`Orbita browser is not exists on path ${ORBITA_BROWSER}, check executablePath param`);
|
|
1050
1103
|
}
|
|
1051
1104
|
|
|
@@ -1071,12 +1124,12 @@ class GoLogin {
|
|
|
1071
1124
|
return this.stopRemote();
|
|
1072
1125
|
}
|
|
1073
1126
|
|
|
1074
|
-
await this.stopAndCommit({ posting:
|
|
1127
|
+
await this.stopAndCommit({ posting: true }, false);
|
|
1075
1128
|
}
|
|
1076
1129
|
|
|
1077
1130
|
async stopLocal(options) {
|
|
1078
1131
|
const opts = options || { posting: false };
|
|
1079
|
-
await this.stopAndCommit(
|
|
1132
|
+
await this.stopAndCommit(opts, true);
|
|
1080
1133
|
}
|
|
1081
1134
|
|
|
1082
1135
|
async waitDebuggingUrl(delay_ms, try_count=0) {
|
|
@@ -1113,7 +1166,7 @@ class GoLogin {
|
|
|
1113
1166
|
}
|
|
1114
1167
|
});
|
|
1115
1168
|
|
|
1116
|
-
if(profileResponse.statusCode
|
|
1169
|
+
if (profileResponse.statusCode === 401){
|
|
1117
1170
|
throw new Error("invalid token");
|
|
1118
1171
|
}
|
|
1119
1172
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gologin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.32",
|
|
4
4
|
"description": "A high-level API to control Orbita browser over GoLogin API",
|
|
5
5
|
"main": "./gologin.js",
|
|
6
6
|
"repository": {
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"requestretry": "^4.1.0",
|
|
27
27
|
"rimraf": "^3.0.2",
|
|
28
28
|
"selenium-webdriver": "^4.0.0-alpha.7",
|
|
29
|
-
"shelljs": "^0.8.4",
|
|
30
29
|
"simple-proxy-agent": "^1.1.0",
|
|
31
30
|
"sqlite": "^4.0.23",
|
|
32
|
-
"sqlite3": "^5.0.2"
|
|
31
|
+
"sqlite3": "^5.0.2",
|
|
32
|
+
"zip-dir": "^2.0.0"
|
|
33
33
|
},
|
|
34
34
|
"bugs": {
|
|
35
35
|
"url": "https://github.com/gologinapp/gologin/issues"
|