steamcommunity 3.45.2 → 3.46.0

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/index.js CHANGED
@@ -1,597 +1,600 @@
1
- const hex2b64 = require('node-bignumber').hex2b64;
2
- const Request = require('request');
3
- const RSA = require('node-bignumber').Key;
4
- const SteamID = require('steamid');
5
-
6
- const Helpers = require('./components/helpers.js');
7
-
8
- const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36";
9
-
10
- require('util').inherits(SteamCommunity, require('events').EventEmitter);
11
-
12
- module.exports = SteamCommunity;
13
-
14
- SteamCommunity.SteamID = SteamID;
15
- SteamCommunity.ConfirmationType = require('./resources/EConfirmationType.js');
16
- SteamCommunity.EResult = require('./resources/EResult.js');
17
- SteamCommunity.EFriendRelationship = require('./resources/EFriendRelationship.js');
18
-
19
-
20
- function SteamCommunity(options) {
21
- options = options || {};
22
-
23
- this._jar = Request.jar();
24
- this._captchaGid = -1;
25
- this._httpRequestID = 0;
26
- this.chatState = SteamCommunity.ChatState.Offline;
27
-
28
- var defaults = {
29
- "jar": this._jar,
30
- "timeout": options.timeout || 50000,
31
- "gzip": true,
32
- "headers": {
33
- "User-Agent": options.userAgent || USER_AGENT
34
- }
35
- };
36
-
37
- if (typeof options == "string") {
38
- options = {
39
- localAddress: options
40
- };
41
- }
42
- this._options = options;
43
-
44
- if (options.localAddress) {
45
- defaults.localAddress = options.localAddress;
46
- }
47
-
48
- this.request = options.request || Request.defaults({"forever": true}); // "forever" indicates that we want a keep-alive agent
49
- this.request = this.request.defaults(defaults);
50
-
51
- // English
52
- this._setCookie(Request.cookie('Steam_Language=english'));
53
-
54
- // UTC
55
- this._setCookie(Request.cookie('timezoneOffset=0,0'));
56
- }
57
-
58
- SteamCommunity.prototype.login = function(details, callback) {
59
- if (!details.accountName || !details.password) {
60
- throw new Error("Missing either accountName or password to login; both are needed");
61
- }
62
-
63
- if (details.steamguard) {
64
- var parts = details.steamguard.split('||');
65
- this._setCookie(Request.cookie('steamMachineAuth' + parts[0] + '=' + encodeURIComponent(parts[1])), true);
66
- }
67
-
68
- var disableMobile = typeof details.disableMobile == 'undefined' ? true : details.disableMobile;
69
-
70
- var self = this;
71
-
72
- // Delete the cache
73
- delete self._profileURL;
74
-
75
- // headers required to convince steam that we're logging in from a mobile device so that we can get the oAuth data
76
- var mobileHeaders = {};
77
- if (!disableMobile) {
78
- mobileHeaders = {
79
- "X-Requested-With": "com.valvesoftware.android.steam.community",
80
- "Referer": "https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client",
81
- "User-Agent": this._options.mobileUserAgent || details.mobileUserAgent || "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
82
- "Accept": "text/javascript, text/html, application/xml, text/xml, */*"
83
- };
84
-
85
- this._setCookie(Request.cookie("mobileClientVersion=0 (2.1.3)"));
86
- this._setCookie(Request.cookie("mobileClient=android"));
87
- } else {
88
- mobileHeaders = {"Referer": "https://steamcommunity.com/login"};
89
- }
90
-
91
- this.httpRequestPost("https://steamcommunity.com/login/getrsakey/", {
92
- "form": {"username": details.accountName},
93
- "headers": mobileHeaders,
94
- "json": true
95
- }, function(err, response, body) {
96
- // Remove the mobile cookies
97
- if (err) {
98
- deleteMobileCookies();
99
- callback(err);
100
- return;
101
- }
102
-
103
- if (!body.publickey_mod || !body.publickey_exp) {
104
- deleteMobileCookies();
105
- callback(new Error("Invalid RSA key received"));
106
- return;
107
- }
108
-
109
- var key = new RSA();
110
- key.setPublic(body.publickey_mod, body.publickey_exp);
111
-
112
- var formObj = {
113
- "captcha_text": details.captcha || "",
114
- "captchagid": self._captchaGid,
115
- "emailauth": details.authCode || "",
116
- "emailsteamid": "",
117
- "password": hex2b64(key.encrypt(details.password)),
118
- "remember_login": "true",
119
- "rsatimestamp": body.timestamp,
120
- "twofactorcode": details.twoFactorCode || "",
121
- "username": details.accountName,
122
- "loginfriendlyname": "",
123
- "donotcache": Date.now()
124
- };
125
-
126
- if (!disableMobile) {
127
- formObj.oauth_client_id = "DE45CD61";
128
- formObj.oauth_scope = "read_profile write_profile read_client write_client";
129
- formObj.loginfriendlyname = "#login_emailauth_friendlyname_mobile";
130
- }
131
-
132
- self.httpRequestPost({
133
- "uri": "https://steamcommunity.com/login/dologin/",
134
- "json": true,
135
- "form": formObj,
136
- "headers": mobileHeaders
137
- }, function(err, response, body) {
138
- deleteMobileCookies();
139
-
140
- if (err) {
141
- callback(err);
142
- return;
143
- }
144
-
145
- var error;
146
- if (!body.success && body.emailauth_needed) {
147
- // Steam Guard (email)
148
- error = new Error("SteamGuard");
149
- error.emaildomain = body.emaildomain;
150
-
151
- callback(error);
152
- } else if (!body.success && body.requires_twofactor) {
153
- // Steam Guard (app)
154
- callback(new Error("SteamGuardMobile"));
155
- } else if (!body.success && body.captcha_needed && body.message.match(/Please verify your humanity/)) {
156
- error = new Error("CAPTCHA");
157
- error.captchaurl = "https://steamcommunity.com/login/rendercaptcha/?gid=" + body.captcha_gid;
158
-
159
- self._captchaGid = body.captcha_gid;
160
-
161
- callback(error);
162
- } else if (!body.success) {
163
- callback(new Error(body.message || "Unknown error"));
164
- } else {
165
- var sessionID = generateSessionID();
166
- var oAuth = {};
167
- self._setCookie(Request.cookie('sessionid=' + sessionID));
168
-
169
- var cookies = self._jar.getCookieString("https://steamcommunity.com").split(';').map(function(cookie) {
170
- return cookie.trim();
171
- });
172
-
173
- if (!disableMobile && body.oauth) {
174
- oAuth = JSON.parse(body.oauth);
175
- self.steamID = new SteamID(oAuth.steamid);
176
- self.oAuthToken = oAuth.oauth_token;
177
- } else {
178
- for(var i = 0; i < cookies.length; i++) {
179
- var parts = cookies[i].split('=');
180
- if(parts[0] == 'steamLogin') {
181
- self.steamID = new SteamID(decodeURIComponent(parts[1]).split('||')[0])
182
- break;
183
- }
184
- }
185
-
186
- self.oAuthToken = null;
187
- }
188
-
189
- // Find the Steam Guard cookie
190
- var steamguard = null;
191
- for (var i = 0; i < cookies.length; i++) {
192
- var parts = cookies[i].split('=');
193
- if(parts[0] == 'steamMachineAuth' + self.steamID) {
194
- steamguard = self.steamID.toString() + '||' + decodeURIComponent(parts[1]);
195
- break;
196
- }
197
- }
198
-
199
- self.setCookies(cookies);
200
-
201
- callback(null, sessionID, cookies, steamguard, disableMobile ? null : oAuth.oauth_token);
202
- }
203
- }, "steamcommunity");
204
- }, "steamcommunity");
205
-
206
- function deleteMobileCookies() {
207
- var cookie = Request.cookie('mobileClientVersion=');
208
- cookie.expires = new Date(0);
209
- self._setCookie(cookie);
210
-
211
- cookie = Request.cookie('mobileClient=');
212
- cookie.expires = new Date(0);
213
- self._setCookie(cookie);
214
- }
215
- };
216
-
217
- /**
218
- * @deprecated
219
- * @param {string} steamguard
220
- * @param {string} token
221
- * @param {function} callback
222
- */
223
- SteamCommunity.prototype.oAuthLogin = function(steamguard, token, callback) {
224
- steamguard = steamguard.split('||');
225
- var steamID = new SteamID(steamguard[0]);
226
-
227
- var self = this;
228
- this.httpRequestPost({
229
- "uri": "https://api.steampowered.com/IMobileAuthService/GetWGToken/v1/",
230
- "form": {
231
- "access_token": token
232
- },
233
- "json": true
234
- }, function(err, response, body) {
235
- if (err) {
236
- callback(err);
237
- return;
238
- }
239
-
240
- if(!body.response || !body.response.token || !body.response.token_secure) {
241
- callback(new Error("Malformed response"));
242
- return;
243
- }
244
-
245
- var cookies = [
246
- 'steamLogin=' + encodeURIComponent(steamID.getSteamID64() + '||' + body.response.token),
247
- 'steamLoginSecure=' + encodeURIComponent(steamID.getSteamID64() + '||' + body.response.token_secure),
248
- 'steamMachineAuth' + steamID.getSteamID64() + '=' + steamguard[1],
249
- 'sessionid=' + self.getSessionID()
250
- ];
251
-
252
- self.setCookies(cookies);
253
- callback(null, self.getSessionID(), cookies);
254
- }, "steamcommunity");
255
- };
256
-
257
- /**
258
- * Get a token that can be used to log onto Steam using steam-user.
259
- * @param {function} callback
260
- */
261
- SteamCommunity.prototype.getClientLogonToken = function(callback) {
262
- this.httpRequestGet({
263
- "uri": "https://steamcommunity.com/chat/clientjstoken",
264
- "json": true
265
- }, (err, res, body) => {
266
- if (err || res.statusCode != 200) {
267
- callback(err ? err : new Error('HTTP error ' + res.statusCode));
268
- return;
269
- }
270
-
271
- if (!body.logged_in) {
272
- let e = new Error('Not Logged In');
273
- callback(e);
274
- this._notifySessionExpired(e);
275
- return;
276
- }
277
-
278
- if (!body.steamid || !body.account_name || !body.token) {
279
- callback(new Error('Malformed response'));
280
- return;
281
- }
282
-
283
- callback(null, {
284
- "steamID": new SteamID(body.steamid),
285
- "accountName": body.account_name,
286
- "webLogonToken": body.token
287
- });
288
- });
289
- };
290
-
291
- SteamCommunity.prototype._setCookie = function(cookie, secure) {
292
- var protocol = secure ? "https" : "http";
293
- cookie.secure = !!secure;
294
-
295
- this._jar.setCookie(cookie.clone(), protocol + "://steamcommunity.com");
296
- this._jar.setCookie(cookie.clone(), protocol + "://store.steampowered.com");
297
- this._jar.setCookie(cookie.clone(), protocol + "://help.steampowered.com");
298
- };
299
-
300
- SteamCommunity.prototype.setCookies = function(cookies) {
301
- cookies.forEach((cookie) => {
302
- var cookieName = cookie.match(/(.+)=/)[1];
303
- if (cookieName == 'steamLogin' || cookieName == 'steamLoginSecure') {
304
- this.steamID = new SteamID(cookie.match(/=(\d+)/)[1]);
305
- }
306
-
307
- this._setCookie(Request.cookie(cookie), !!(cookieName.match(/^steamMachineAuth/) || cookieName.match(/Secure$/)));
308
- });
309
-
310
- // The account we're logged in as might have changed, so verify that our mobile access token (if any) is still valid
311
- // for this account.
312
- this._verifyMobileAccessToken();
313
- };
314
-
315
- SteamCommunity.prototype.getSessionID = function(host = "http://steamcommunity.com") {
316
- var cookies = this._jar.getCookieString(host).split(';');
317
- for(var i = 0; i < cookies.length; i++) {
318
- var match = cookies[i].trim().match(/([^=]+)=(.+)/);
319
- if(match[1] == 'sessionid') {
320
- return decodeURIComponent(match[2]);
321
- }
322
- }
323
-
324
- var sessionID = generateSessionID();
325
- this._setCookie(Request.cookie('sessionid=' + sessionID));
326
- return sessionID;
327
- };
328
-
329
- function generateSessionID() {
330
- return require('crypto').randomBytes(12).toString('hex');
331
- }
332
-
333
- SteamCommunity.prototype.parentalUnlock = function(pin, callback) {
334
- var self = this;
335
- var sessionID = self.getSessionID();
336
-
337
- this.httpRequestPost("https://steamcommunity.com/parental/ajaxunlock", {
338
- "json": true,
339
- "form": {
340
- "pin": pin,
341
- "sessionid": sessionID
342
- }
343
- }, function(err, response, body) {
344
- if(!callback) {
345
- return;
346
- }
347
-
348
- if (err) {
349
- callback(err);
350
- return;
351
- }
352
-
353
- if (!body || typeof body.success !== 'boolean') {
354
- callback("Invalid response");
355
- return;
356
- }
357
-
358
- if (!body.success) {
359
- switch (body.eresult) {
360
- case 15:
361
- callback("Incorrect PIN");
362
- break;
363
-
364
- case 25:
365
- callback("Too many invalid PIN attempts");
366
- break;
367
-
368
- default:
369
- callback("Error " + body.eresult);
370
- }
371
-
372
- return;
373
- }
374
-
375
- callback();
376
- }.bind(this), "steamcommunity");
377
- };
378
-
379
- SteamCommunity.prototype.getNotifications = function(callback) {
380
- var self = this;
381
- this.httpRequestGet({
382
- "uri": "https://steamcommunity.com/actions/GetNotificationCounts",
383
- "json": true
384
- }, function(err, response, body) {
385
- if (err) {
386
- callback(err);
387
- return;
388
- }
389
-
390
- if (!body || !body.notifications) {
391
- callback(new Error("Malformed response"));
392
- return;
393
- }
394
-
395
- var notifications = {
396
- "trades": body.notifications[1] || 0,
397
- "gameTurns": body.notifications[2] || 0,
398
- "moderatorMessages": body.notifications[3] || 0,
399
- "comments": body.notifications[4] || 0,
400
- "items": body.notifications[5] || 0,
401
- "invites": body.notifications[6] || 0,
402
- // dunno about 7
403
- "gifts": body.notifications[8] || 0,
404
- "chat": body.notifications[9] || 0,
405
- "helpRequestReplies": body.notifications[10] || 0,
406
- "accountAlerts": body.notifications[11] || 0
407
- };
408
-
409
- callback(null, notifications);
410
- }, "steamcommunity");
411
- };
412
-
413
- SteamCommunity.prototype.resetItemNotifications = function(callback) {
414
- var self = this;
415
- this.httpRequestGet("https://steamcommunity.com/my/inventory", function(err, response, body) {
416
- if(!callback) {
417
- return;
418
- }
419
-
420
- callback(err || null);
421
- }, "steamcommunity");
422
- };
423
-
424
- SteamCommunity.prototype.loggedIn = function(callback) {
425
- this.httpRequestGet({
426
- "uri": "https://steamcommunity.com/my",
427
- "followRedirect": false,
428
- "checkHttpError": false
429
- }, function(err, response, body) {
430
- if(err || (response.statusCode != 302 && response.statusCode != 403)) {
431
- callback(err || new Error("HTTP error " + response.statusCode));
432
- return;
433
- }
434
-
435
- if(response.statusCode == 403) {
436
- callback(null, true, true);
437
- return;
438
- }
439
-
440
- callback(null, !!response.headers.location.match(/steamcommunity\.com(\/(id|profiles)\/[^\/]+)\/?/), false);
441
- }, "steamcommunity");
442
- };
443
-
444
- SteamCommunity.prototype.getTradeURL = function(callback) {
445
- this._myProfile("tradeoffers/privacy", null, (err, response, body) => {
446
- if (err) {
447
- callback(err);
448
- return;
449
- }
450
-
451
- var match = body.match(/https?:\/\/(www.)?steamcommunity.com\/tradeoffer\/new\/?\?partner=\d+(&|&amp;)token=([a-zA-Z0-9-_]+)/);
452
- if (match) {
453
- var token = match[3];
454
- callback(null, match[0], token);
455
- } else {
456
- callback(new Error("Malformed response"));
457
- }
458
- }, "steamcommunity");
459
- };
460
-
461
- SteamCommunity.prototype.changeTradeURL = function(callback) {
462
- this._myProfile("tradeoffers/newtradeurl", {"sessionid": this.getSessionID()}, (err, response, body) => {
463
- if (!callback) {
464
- return;
465
- }
466
-
467
- if (!body || typeof body !== "string" || body.length < 3 || body.indexOf('"') !== 0) {
468
- callback(new Error("Malformed response"));
469
- return;
470
- }
471
-
472
- var newToken = body.replace(/"/g, ''); //"t1o2k3e4n" => t1o2k3e4n
473
- callback(null, "https://steamcommunity.com/tradeoffer/new/?partner=" + this.steamID.accountid + "&token=" + newToken, newToken);
474
- }, "steamcommunity");
475
- };
476
-
477
- /**
478
- * Clear your profile name (alias) history.
479
- * @param {function} callback
480
- */
481
- SteamCommunity.prototype.clearPersonaNameHistory = function(callback) {
482
- this._myProfile("ajaxclearaliashistory/", {"sessionid": this.getSessionID()}, (err, res, body) => {
483
- if (!callback) {
484
- return;
485
- }
486
-
487
- if (err) {
488
- return callback(err);
489
- }
490
-
491
- if (res.statusCode != 200) {
492
- return callback(new Error("HTTP error " + res.statusCode));
493
- }
494
-
495
- try {
496
- body = JSON.parse(body);
497
- callback(Helpers.eresultError(body.success));
498
- } catch (ex) {
499
- return callback(new Error("Malformed response"));
500
- }
501
- });
502
- };
503
-
504
- SteamCommunity.prototype._myProfile = function(endpoint, form, callback) {
505
- var self = this;
506
-
507
- if (this._profileURL) {
508
- completeRequest(this._profileURL);
509
- } else {
510
- this.httpRequest("https://steamcommunity.com/my", {"followRedirect": false}, function(err, response, body) {
511
- if(err || response.statusCode != 302) {
512
- callback(err || "HTTP error " + response.statusCode);
513
- return;
514
- }
515
-
516
- var match = response.headers.location.match(/steamcommunity\.com(\/(id|profiles)\/[^\/]+)\/?/);
517
- if(!match) {
518
- callback(new Error("Can't get profile URL"));
519
- return;
520
- }
521
-
522
- self._profileURL = match[1];
523
- setTimeout(function () {
524
- delete self._profileURL; // delete the cache
525
- }, 60000).unref();
526
-
527
- completeRequest(match[1]);
528
- }, "steamcommunity");
529
- }
530
-
531
- function completeRequest(url) {
532
- var options = endpoint.endpoint ? endpoint : {};
533
- options.uri = "https://steamcommunity.com" + url + "/" + (endpoint.endpoint || endpoint);
534
-
535
- if (form) {
536
- options.method = "POST";
537
- options.form = form;
538
- options.followAllRedirects = true;
539
- } else if (!options.method) {
540
- options.method = "GET";
541
- }
542
-
543
- self.httpRequest(options, callback, "steamcommunity");
544
- }
545
- };
546
-
547
- /**
548
- * Returns an object whose keys are 64-bit SteamIDs, and whose values are values from the EFriendRelationship enum.
549
- * Therefore, you can deduce your friends or blocked list from this object.
550
- * @param {function} callback
551
- */
552
- SteamCommunity.prototype.getFriendsList = function(callback) {
553
- this.httpRequestGet({
554
- "uri": "https://steamcommunity.com/textfilter/ajaxgetfriendslist",
555
- "json": true
556
- }, (err, res, body) => {
557
- if (err) {
558
- callback(err ? err : new Error('HTTP error ' + res.statusCode));
559
- return;
560
- }
561
-
562
- if (body.success != 1) {
563
- callback(Helpers.eresultError(body.success));
564
- return;
565
- }
566
-
567
- if (!body.friendslist || !body.friendslist.friends) {
568
- callback(new Error('Malformed response'));
569
- return;
570
- }
571
-
572
- const friends = {};
573
- body.friendslist.friends.forEach(friend => (friends[friend.ulfriendid] = friend.efriendrelationship));
574
- callback(null, friends);
575
- });
576
- };
577
-
578
- require('./components/http.js');
579
- require('./components/chat.js');
580
- require('./components/profile.js');
581
- require('./components/market.js');
582
- require('./components/groups.js');
583
- require('./components/users.js');
584
- require('./components/inventoryhistory.js');
585
- require('./components/webapi.js');
586
- require('./components/twofactor.js');
587
- require('./components/confirmations.js');
588
- require('./components/help.js');
589
- require('./classes/CMarketItem.js');
590
- require('./classes/CMarketSearchResult.js');
591
- require('./classes/CSteamGroup.js');
592
- require('./classes/CSteamUser.js');
593
-
594
- /**
595
- @callback SteamCommunity~genericErrorCallback
596
- @param {Error|null} err - An Error object on failure, or null on success
597
- */
1
+ const hex2b64 = require('node-bignumber').hex2b64;
2
+ const Request = require('request');
3
+ const RSA = require('node-bignumber').Key;
4
+ const SteamID = require('steamid');
5
+
6
+ const Helpers = require('./components/helpers.js');
7
+
8
+ const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36";
9
+
10
+ require('util').inherits(SteamCommunity, require('events').EventEmitter);
11
+
12
+ module.exports = SteamCommunity;
13
+
14
+ SteamCommunity.SteamID = SteamID;
15
+ SteamCommunity.ConfirmationType = require('./resources/EConfirmationType.js');
16
+ SteamCommunity.EResult = require('./resources/EResult.js');
17
+ SteamCommunity.ESharedFileType = require('./resources/ESharedFileType.js');
18
+ SteamCommunity.EFriendRelationship = require('./resources/EFriendRelationship.js');
19
+
20
+
21
+ function SteamCommunity(options) {
22
+ options = options || {};
23
+
24
+ this._jar = Request.jar();
25
+ this._captchaGid = -1;
26
+ this._httpRequestID = 0;
27
+ this.chatState = SteamCommunity.ChatState.Offline;
28
+
29
+ var defaults = {
30
+ "jar": this._jar,
31
+ "timeout": options.timeout || 50000,
32
+ "gzip": true,
33
+ "headers": {
34
+ "User-Agent": options.userAgent || USER_AGENT
35
+ }
36
+ };
37
+
38
+ if (typeof options == "string") {
39
+ options = {
40
+ localAddress: options
41
+ };
42
+ }
43
+ this._options = options;
44
+
45
+ if (options.localAddress) {
46
+ defaults.localAddress = options.localAddress;
47
+ }
48
+
49
+ this.request = options.request || Request.defaults({"forever": true}); // "forever" indicates that we want a keep-alive agent
50
+ this.request = this.request.defaults(defaults);
51
+
52
+ // English
53
+ this._setCookie(Request.cookie('Steam_Language=english'));
54
+
55
+ // UTC
56
+ this._setCookie(Request.cookie('timezoneOffset=0,0'));
57
+ }
58
+
59
+ SteamCommunity.prototype.login = function(details, callback) {
60
+ if (!details.accountName || !details.password) {
61
+ throw new Error("Missing either accountName or password to login; both are needed");
62
+ }
63
+
64
+ if (details.steamguard) {
65
+ var parts = details.steamguard.split('||');
66
+ this._setCookie(Request.cookie('steamMachineAuth' + parts[0] + '=' + encodeURIComponent(parts[1])), true);
67
+ }
68
+
69
+ var disableMobile = typeof details.disableMobile == 'undefined' ? true : details.disableMobile;
70
+
71
+ var self = this;
72
+
73
+ // Delete the cache
74
+ delete self._profileURL;
75
+
76
+ // headers required to convince steam that we're logging in from a mobile device so that we can get the oAuth data
77
+ var mobileHeaders = {};
78
+ if (!disableMobile) {
79
+ mobileHeaders = {
80
+ "X-Requested-With": "com.valvesoftware.android.steam.community",
81
+ "Referer": "https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client",
82
+ "User-Agent": this._options.mobileUserAgent || details.mobileUserAgent || "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
83
+ "Accept": "text/javascript, text/html, application/xml, text/xml, */*"
84
+ };
85
+
86
+ this._setCookie(Request.cookie("mobileClientVersion=0 (2.1.3)"));
87
+ this._setCookie(Request.cookie("mobileClient=android"));
88
+ } else {
89
+ mobileHeaders = {"Referer": "https://steamcommunity.com/login"};
90
+ }
91
+
92
+ this.httpRequestPost("https://steamcommunity.com/login/getrsakey/", {
93
+ "form": {"username": details.accountName},
94
+ "headers": mobileHeaders,
95
+ "json": true
96
+ }, function(err, response, body) {
97
+ // Remove the mobile cookies
98
+ if (err) {
99
+ deleteMobileCookies();
100
+ callback(err);
101
+ return;
102
+ }
103
+
104
+ if (!body.publickey_mod || !body.publickey_exp) {
105
+ deleteMobileCookies();
106
+ callback(new Error("Invalid RSA key received"));
107
+ return;
108
+ }
109
+
110
+ var key = new RSA();
111
+ key.setPublic(body.publickey_mod, body.publickey_exp);
112
+
113
+ var formObj = {
114
+ "captcha_text": details.captcha || "",
115
+ "captchagid": self._captchaGid,
116
+ "emailauth": details.authCode || "",
117
+ "emailsteamid": "",
118
+ "password": hex2b64(key.encrypt(details.password)),
119
+ "remember_login": "true",
120
+ "rsatimestamp": body.timestamp,
121
+ "twofactorcode": details.twoFactorCode || "",
122
+ "username": details.accountName,
123
+ "loginfriendlyname": "",
124
+ "donotcache": Date.now()
125
+ };
126
+
127
+ if (!disableMobile) {
128
+ formObj.oauth_client_id = "DE45CD61";
129
+ formObj.oauth_scope = "read_profile write_profile read_client write_client";
130
+ formObj.loginfriendlyname = "#login_emailauth_friendlyname_mobile";
131
+ }
132
+
133
+ self.httpRequestPost({
134
+ "uri": "https://steamcommunity.com/login/dologin/",
135
+ "json": true,
136
+ "form": formObj,
137
+ "headers": mobileHeaders
138
+ }, function(err, response, body) {
139
+ deleteMobileCookies();
140
+
141
+ if (err) {
142
+ callback(err);
143
+ return;
144
+ }
145
+
146
+ var error;
147
+ if (!body.success && body.emailauth_needed) {
148
+ // Steam Guard (email)
149
+ error = new Error("SteamGuard");
150
+ error.emaildomain = body.emaildomain;
151
+
152
+ callback(error);
153
+ } else if (!body.success && body.requires_twofactor) {
154
+ // Steam Guard (app)
155
+ callback(new Error("SteamGuardMobile"));
156
+ } else if (!body.success && body.captcha_needed && body.message.match(/Please verify your humanity/)) {
157
+ error = new Error("CAPTCHA");
158
+ error.captchaurl = "https://steamcommunity.com/login/rendercaptcha/?gid=" + body.captcha_gid;
159
+
160
+ self._captchaGid = body.captcha_gid;
161
+
162
+ callback(error);
163
+ } else if (!body.success) {
164
+ callback(new Error(body.message || "Unknown error"));
165
+ } else {
166
+ var sessionID = generateSessionID();
167
+ var oAuth = {};
168
+ self._setCookie(Request.cookie('sessionid=' + sessionID));
169
+
170
+ var cookies = self._jar.getCookieString("https://steamcommunity.com").split(';').map(function(cookie) {
171
+ return cookie.trim();
172
+ });
173
+
174
+ if (!disableMobile && body.oauth) {
175
+ oAuth = JSON.parse(body.oauth);
176
+ self.steamID = new SteamID(oAuth.steamid);
177
+ self.oAuthToken = oAuth.oauth_token;
178
+ } else {
179
+ for(var i = 0; i < cookies.length; i++) {
180
+ var parts = cookies[i].split('=');
181
+ if(parts[0] == 'steamLogin') {
182
+ self.steamID = new SteamID(decodeURIComponent(parts[1]).split('||')[0])
183
+ break;
184
+ }
185
+ }
186
+
187
+ self.oAuthToken = null;
188
+ }
189
+
190
+ // Find the Steam Guard cookie
191
+ var steamguard = null;
192
+ for (var i = 0; i < cookies.length; i++) {
193
+ var parts = cookies[i].split('=');
194
+ if(parts[0] == 'steamMachineAuth' + self.steamID) {
195
+ steamguard = self.steamID.toString() + '||' + decodeURIComponent(parts[1]);
196
+ break;
197
+ }
198
+ }
199
+
200
+ self.setCookies(cookies);
201
+
202
+ callback(null, sessionID, cookies, steamguard, disableMobile ? null : oAuth.oauth_token);
203
+ }
204
+ }, "steamcommunity");
205
+ }, "steamcommunity");
206
+
207
+ function deleteMobileCookies() {
208
+ var cookie = Request.cookie('mobileClientVersion=');
209
+ cookie.expires = new Date(0);
210
+ self._setCookie(cookie);
211
+
212
+ cookie = Request.cookie('mobileClient=');
213
+ cookie.expires = new Date(0);
214
+ self._setCookie(cookie);
215
+ }
216
+ };
217
+
218
+ /**
219
+ * @deprecated
220
+ * @param {string} steamguard
221
+ * @param {string} token
222
+ * @param {function} callback
223
+ */
224
+ SteamCommunity.prototype.oAuthLogin = function(steamguard, token, callback) {
225
+ steamguard = steamguard.split('||');
226
+ var steamID = new SteamID(steamguard[0]);
227
+
228
+ var self = this;
229
+ this.httpRequestPost({
230
+ "uri": "https://api.steampowered.com/IMobileAuthService/GetWGToken/v1/",
231
+ "form": {
232
+ "access_token": token
233
+ },
234
+ "json": true
235
+ }, function(err, response, body) {
236
+ if (err) {
237
+ callback(err);
238
+ return;
239
+ }
240
+
241
+ if(!body.response || !body.response.token || !body.response.token_secure) {
242
+ callback(new Error("Malformed response"));
243
+ return;
244
+ }
245
+
246
+ var cookies = [
247
+ 'steamLogin=' + encodeURIComponent(steamID.getSteamID64() + '||' + body.response.token),
248
+ 'steamLoginSecure=' + encodeURIComponent(steamID.getSteamID64() + '||' + body.response.token_secure),
249
+ 'steamMachineAuth' + steamID.getSteamID64() + '=' + steamguard[1],
250
+ 'sessionid=' + self.getSessionID()
251
+ ];
252
+
253
+ self.setCookies(cookies);
254
+ callback(null, self.getSessionID(), cookies);
255
+ }, "steamcommunity");
256
+ };
257
+
258
+ /**
259
+ * Get a token that can be used to log onto Steam using steam-user.
260
+ * @param {function} callback
261
+ */
262
+ SteamCommunity.prototype.getClientLogonToken = function(callback) {
263
+ this.httpRequestGet({
264
+ "uri": "https://steamcommunity.com/chat/clientjstoken",
265
+ "json": true
266
+ }, (err, res, body) => {
267
+ if (err || res.statusCode != 200) {
268
+ callback(err ? err : new Error('HTTP error ' + res.statusCode));
269
+ return;
270
+ }
271
+
272
+ if (!body.logged_in) {
273
+ let e = new Error('Not Logged In');
274
+ callback(e);
275
+ this._notifySessionExpired(e);
276
+ return;
277
+ }
278
+
279
+ if (!body.steamid || !body.account_name || !body.token) {
280
+ callback(new Error('Malformed response'));
281
+ return;
282
+ }
283
+
284
+ callback(null, {
285
+ "steamID": new SteamID(body.steamid),
286
+ "accountName": body.account_name,
287
+ "webLogonToken": body.token
288
+ });
289
+ });
290
+ };
291
+
292
+ SteamCommunity.prototype._setCookie = function(cookie, secure) {
293
+ var protocol = secure ? "https" : "http";
294
+ cookie.secure = !!secure;
295
+
296
+ this._jar.setCookie(cookie.clone(), protocol + "://steamcommunity.com");
297
+ this._jar.setCookie(cookie.clone(), protocol + "://store.steampowered.com");
298
+ this._jar.setCookie(cookie.clone(), protocol + "://help.steampowered.com");
299
+ };
300
+
301
+ SteamCommunity.prototype.setCookies = function(cookies) {
302
+ cookies.forEach((cookie) => {
303
+ var cookieName = cookie.match(/(.+)=/)[1];
304
+ if (cookieName == 'steamLogin' || cookieName == 'steamLoginSecure') {
305
+ this.steamID = new SteamID(cookie.match(/=(\d+)/)[1]);
306
+ }
307
+
308
+ this._setCookie(Request.cookie(cookie), !!(cookieName.match(/^steamMachineAuth/) || cookieName.match(/Secure$/)));
309
+ });
310
+
311
+ // The account we're logged in as might have changed, so verify that our mobile access token (if any) is still valid
312
+ // for this account.
313
+ this._verifyMobileAccessToken();
314
+ };
315
+
316
+ SteamCommunity.prototype.getSessionID = function(host = "http://steamcommunity.com") {
317
+ var cookies = this._jar.getCookieString(host).split(';');
318
+ for(var i = 0; i < cookies.length; i++) {
319
+ var match = cookies[i].trim().match(/([^=]+)=(.+)/);
320
+ if(match[1] == 'sessionid') {
321
+ return decodeURIComponent(match[2]);
322
+ }
323
+ }
324
+
325
+ var sessionID = generateSessionID();
326
+ this._setCookie(Request.cookie('sessionid=' + sessionID));
327
+ return sessionID;
328
+ };
329
+
330
+ function generateSessionID() {
331
+ return require('crypto').randomBytes(12).toString('hex');
332
+ }
333
+
334
+ SteamCommunity.prototype.parentalUnlock = function(pin, callback) {
335
+ var self = this;
336
+ var sessionID = self.getSessionID();
337
+
338
+ this.httpRequestPost("https://steamcommunity.com/parental/ajaxunlock", {
339
+ "json": true,
340
+ "form": {
341
+ "pin": pin,
342
+ "sessionid": sessionID
343
+ }
344
+ }, function(err, response, body) {
345
+ if(!callback) {
346
+ return;
347
+ }
348
+
349
+ if (err) {
350
+ callback(err);
351
+ return;
352
+ }
353
+
354
+ if (!body || typeof body.success !== 'boolean') {
355
+ callback("Invalid response");
356
+ return;
357
+ }
358
+
359
+ if (!body.success) {
360
+ switch (body.eresult) {
361
+ case 15:
362
+ callback("Incorrect PIN");
363
+ break;
364
+
365
+ case 25:
366
+ callback("Too many invalid PIN attempts");
367
+ break;
368
+
369
+ default:
370
+ callback("Error " + body.eresult);
371
+ }
372
+
373
+ return;
374
+ }
375
+
376
+ callback();
377
+ }.bind(this), "steamcommunity");
378
+ };
379
+
380
+ SteamCommunity.prototype.getNotifications = function(callback) {
381
+ var self = this;
382
+ this.httpRequestGet({
383
+ "uri": "https://steamcommunity.com/actions/GetNotificationCounts",
384
+ "json": true
385
+ }, function(err, response, body) {
386
+ if (err) {
387
+ callback(err);
388
+ return;
389
+ }
390
+
391
+ if (!body || !body.notifications) {
392
+ callback(new Error("Malformed response"));
393
+ return;
394
+ }
395
+
396
+ var notifications = {
397
+ "trades": body.notifications[1] || 0,
398
+ "gameTurns": body.notifications[2] || 0,
399
+ "moderatorMessages": body.notifications[3] || 0,
400
+ "comments": body.notifications[4] || 0,
401
+ "items": body.notifications[5] || 0,
402
+ "invites": body.notifications[6] || 0,
403
+ // dunno about 7
404
+ "gifts": body.notifications[8] || 0,
405
+ "chat": body.notifications[9] || 0,
406
+ "helpRequestReplies": body.notifications[10] || 0,
407
+ "accountAlerts": body.notifications[11] || 0
408
+ };
409
+
410
+ callback(null, notifications);
411
+ }, "steamcommunity");
412
+ };
413
+
414
+ SteamCommunity.prototype.resetItemNotifications = function(callback) {
415
+ var self = this;
416
+ this.httpRequestGet("https://steamcommunity.com/my/inventory", function(err, response, body) {
417
+ if(!callback) {
418
+ return;
419
+ }
420
+
421
+ callback(err || null);
422
+ }, "steamcommunity");
423
+ };
424
+
425
+ SteamCommunity.prototype.loggedIn = function(callback) {
426
+ this.httpRequestGet({
427
+ "uri": "https://steamcommunity.com/my",
428
+ "followRedirect": false,
429
+ "checkHttpError": false
430
+ }, function(err, response, body) {
431
+ if(err || (response.statusCode != 302 && response.statusCode != 403)) {
432
+ callback(err || new Error("HTTP error " + response.statusCode));
433
+ return;
434
+ }
435
+
436
+ if(response.statusCode == 403) {
437
+ callback(null, true, true);
438
+ return;
439
+ }
440
+
441
+ callback(null, !!response.headers.location.match(/steamcommunity\.com(\/(id|profiles)\/[^\/]+)\/?/), false);
442
+ }, "steamcommunity");
443
+ };
444
+
445
+ SteamCommunity.prototype.getTradeURL = function(callback) {
446
+ this._myProfile("tradeoffers/privacy", null, (err, response, body) => {
447
+ if (err) {
448
+ callback(err);
449
+ return;
450
+ }
451
+
452
+ var match = body.match(/https?:\/\/(www.)?steamcommunity.com\/tradeoffer\/new\/?\?partner=\d+(&|&amp;)token=([a-zA-Z0-9-_]+)/);
453
+ if (match) {
454
+ var token = match[3];
455
+ callback(null, match[0], token);
456
+ } else {
457
+ callback(new Error("Malformed response"));
458
+ }
459
+ }, "steamcommunity");
460
+ };
461
+
462
+ SteamCommunity.prototype.changeTradeURL = function(callback) {
463
+ this._myProfile("tradeoffers/newtradeurl", {"sessionid": this.getSessionID()}, (err, response, body) => {
464
+ if (!callback) {
465
+ return;
466
+ }
467
+
468
+ if (!body || typeof body !== "string" || body.length < 3 || body.indexOf('"') !== 0) {
469
+ callback(new Error("Malformed response"));
470
+ return;
471
+ }
472
+
473
+ var newToken = body.replace(/"/g, ''); //"t1o2k3e4n" => t1o2k3e4n
474
+ callback(null, "https://steamcommunity.com/tradeoffer/new/?partner=" + this.steamID.accountid + "&token=" + newToken, newToken);
475
+ }, "steamcommunity");
476
+ };
477
+
478
+ /**
479
+ * Clear your profile name (alias) history.
480
+ * @param {function} callback
481
+ */
482
+ SteamCommunity.prototype.clearPersonaNameHistory = function(callback) {
483
+ this._myProfile("ajaxclearaliashistory/", {"sessionid": this.getSessionID()}, (err, res, body) => {
484
+ if (!callback) {
485
+ return;
486
+ }
487
+
488
+ if (err) {
489
+ return callback(err);
490
+ }
491
+
492
+ if (res.statusCode != 200) {
493
+ return callback(new Error("HTTP error " + res.statusCode));
494
+ }
495
+
496
+ try {
497
+ body = JSON.parse(body);
498
+ callback(Helpers.eresultError(body.success));
499
+ } catch (ex) {
500
+ return callback(new Error("Malformed response"));
501
+ }
502
+ });
503
+ };
504
+
505
+ SteamCommunity.prototype._myProfile = function(endpoint, form, callback) {
506
+ var self = this;
507
+
508
+ if (this._profileURL) {
509
+ completeRequest(this._profileURL);
510
+ } else {
511
+ this.httpRequest("https://steamcommunity.com/my", {"followRedirect": false}, function(err, response, body) {
512
+ if(err || response.statusCode != 302) {
513
+ callback(err || "HTTP error " + response.statusCode);
514
+ return;
515
+ }
516
+
517
+ var match = response.headers.location.match(/steamcommunity\.com(\/(id|profiles)\/[^\/]+)\/?/);
518
+ if(!match) {
519
+ callback(new Error("Can't get profile URL"));
520
+ return;
521
+ }
522
+
523
+ self._profileURL = match[1];
524
+ setTimeout(function () {
525
+ delete self._profileURL; // delete the cache
526
+ }, 60000).unref();
527
+
528
+ completeRequest(match[1]);
529
+ }, "steamcommunity");
530
+ }
531
+
532
+ function completeRequest(url) {
533
+ var options = endpoint.endpoint ? endpoint : {};
534
+ options.uri = "https://steamcommunity.com" + url + "/" + (endpoint.endpoint || endpoint);
535
+
536
+ if (form) {
537
+ options.method = "POST";
538
+ options.form = form;
539
+ options.followAllRedirects = true;
540
+ } else if (!options.method) {
541
+ options.method = "GET";
542
+ }
543
+
544
+ self.httpRequest(options, callback, "steamcommunity");
545
+ }
546
+ };
547
+
548
+ /**
549
+ * Returns an object whose keys are 64-bit SteamIDs, and whose values are values from the EFriendRelationship enum.
550
+ * Therefore, you can deduce your friends or blocked list from this object.
551
+ * @param {function} callback
552
+ */
553
+ SteamCommunity.prototype.getFriendsList = function(callback) {
554
+ this.httpRequestGet({
555
+ "uri": "https://steamcommunity.com/textfilter/ajaxgetfriendslist",
556
+ "json": true
557
+ }, (err, res, body) => {
558
+ if (err) {
559
+ callback(err ? err : new Error('HTTP error ' + res.statusCode));
560
+ return;
561
+ }
562
+
563
+ if (body.success != 1) {
564
+ callback(Helpers.eresultError(body.success));
565
+ return;
566
+ }
567
+
568
+ if (!body.friendslist || !body.friendslist.friends) {
569
+ callback(new Error('Malformed response'));
570
+ return;
571
+ }
572
+
573
+ const friends = {};
574
+ body.friendslist.friends.forEach(friend => (friends[friend.ulfriendid] = friend.efriendrelationship));
575
+ callback(null, friends);
576
+ });
577
+ };
578
+
579
+ require('./components/http.js');
580
+ require('./components/chat.js');
581
+ require('./components/profile.js');
582
+ require('./components/market.js');
583
+ require('./components/groups.js');
584
+ require('./components/users.js');
585
+ require('./components/sharedfiles.js');
586
+ require('./components/inventoryhistory.js');
587
+ require('./components/webapi.js');
588
+ require('./components/twofactor.js');
589
+ require('./components/confirmations.js');
590
+ require('./components/help.js');
591
+ require('./classes/CMarketItem.js');
592
+ require('./classes/CMarketSearchResult.js');
593
+ require('./classes/CSteamGroup.js');
594
+ require('./classes/CSteamSharedFile.js');
595
+ require('./classes/CSteamUser.js');
596
+
597
+ /**
598
+ @callback SteamCommunity~genericErrorCallback
599
+ @param {Error|null} err - An Error object on failure, or null on success
600
+ */