Compare commits

...

67 Commits

Author SHA1 Message Date
Alex Corn
fa8d897590 3.50.3 2026-07-13 12:50:33 -04:00
Alex Corn
f7fe587312 Send correct user-agent for mobileconf requests
(fixes #371)
2026-07-13 12:50:15 -04:00
Alex Corn
08d14f19e6 3.50.2 2026-07-12 17:18:42 -04:00
DoctorMcKay
cfed757eab Merge pull request #369 from lrftw/fix/login-timeout
Fix login hanging indefinitely on steam-session timeout
2026-07-12 17:09:58 -04:00
DoctorMcKay
63defbb643 Merge pull request #370 from GVRLNKMK/fix-ceconitem-tradable-after-crash
Fix CEconItem crash when "Tradable/Marketable After" date isn't day-first
2026-07-12 17:09:19 -04:00
GVRLNKMK
6e20fbe299 Fix CEconItem crash when Tradable/Marketable After date isn't day-first
CEconItem destructured the day-first date regex match without a null
check, throwing 'match is not iterable' for CS2 items whose
owner_descriptions use the legacy month-first format (e.g. 'Tradable/
Marketable After Jul 11, 2025 (2:00:00)'). Running in the constructor,
this made getInventoryContents()/getUserInventoryContents() reject the
whole inventory.

Guard the null match, fall back to parsing the legacy month-first
format, and only set cache_expiration for a valid date. Day-first
strings are unchanged; backwards-compatible.
2026-07-10 17:25:18 +03:00
Lucas
59090242f9 Fix login hanging indefinitely on steam-session timeout
Modern login in components/login.js listens for 'authenticated' and
'error' events from steam-session's LoginSession, but not the 'timeout'
event. When loginTimeout (default 30s) elapses, steam-session emits
'timeout' and calls cancelLoginAttempt() without emitting an 'error'
event, causing the Promise to never settle and the login callback to
never be called.

Add a 'timeout' event listener that rejects the Promise with a
descriptive error.
2026-07-03 10:02:04 +02:00
Alex Corn
00e82f7e79 3.50.1 2026-06-28 17:48:51 -04:00
DoctorMcKay
7b901b147b Merge pull request #367 from ricardocefet2018/master
fix: Invalid time value
2026-06-28 17:44:21 -04:00
Ricardo Rocha
0f7fc98ab5 fix: Invalid time value 2026-06-26 19:14:28 -03:00
Alex Corn
2a12174a7c 3.50.0 2026-03-27 04:32:44 -04:00
DoctorMcKay
caa76ee84b Merge pull request #365 from DarkGL/feat/asset-properties
feat: Add asset_properties support to getInventoryContents
2026-03-27 04:29:47 -04:00
Rafal Wiecek
bc8893fedd feat: add asset properties to inventory items 2026-03-16 15:52:32 +01:00
Alex Corn
d3e90f6fd3 3.49.0 2025-07-19 05:00:47 -04:00
Alex Corn
a61b50b7a2 Added acknowledgeTradeProtection method 2025-07-19 04:59:15 -04:00
Alex Corn
39fe4a4106 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	package.json
2025-07-19 04:49:23 -04:00
Alex Corn
0d991c2655 3.48.8 2025-05-28 05:23:39 -04:00
Alex Corn
0a307de9b9 Prevent descriptions overwriting base econ item properties 2025-05-28 05:23:25 -04:00
Alex Corn
c0b8dcf3a2 3.48.7 2025-05-27 20:27:10 -04:00
DoctorMcKay
dcf00b4ea1 Merge pull request #354 from metzz1/master
fix: steam now only accepts 1000 <
2025-05-27 20:26:40 -04:00
metzz
ee0cc34512 fix: steam now only accepts 1000 < 2025-05-28 03:08:12 +03:00
Alex Corn
c52533ea06 3.48.6 2025-02-12 03:16:04 -05:00
Alex Corn
67774f86f7 Handle "empty" CS2 inventories that aren't actually empty 2025-02-12 03:15:54 -05:00
Alex Corn
2f03e09f50 Require steam-session 1.9.1 2025-02-12 03:05:15 -05:00
Alex Corn
2868b1f45f Fixed malformed sessionid returned in login callback 2025-02-12 03:05:07 -05:00
Alex Corn
ac222ef8c3 Add origin header to all non-GET requests 2025-02-12 03:04:45 -05:00
Alex Corn
4b8799ddd4 3.48.5 2024-11-02 02:54:44 -04:00
Alex Corn
f02f85a2aa Don't error out if a CS inventory has no visible items 2024-11-02 02:54:16 -04:00
Alex Corn
4948cbeac0 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	package.json
2024-11-02 02:49:14 -04:00
Alex Corn
1c1ff82543 3.48.4 2024-10-05 18:50:47 -04:00
Alex Corn
63015259af Updated readme 2024-10-05 18:47:05 -04:00
Alex Corn
ad67805ad9 Prevent committing twofactor files to git 2024-10-05 18:45:26 -04:00
DoctorMcKay
3347d87f29 Merge pull request #347 from benschool/master
Fixes cache_expiration restore for CS2 Items
2024-10-05 18:41:48 -04:00
Benjamin Tyler
c97351543a Fixes cache_expiration restore for CS2 Items
As of Oct 2024, CS2 Item owner_description has changed from "Tradable After" to "Tradable/Marketable After".
2024-10-04 16:04:47 +01:00
DoctorMcKay
1067d4572e Merge pull request #341 from makss/reduce_redirects
Reduce Steam redirects
2024-04-29 10:21:41 -04:00
makss
49a7165052 Reduce Steam redirects 2024-04-29 16:40:01 +03:00
Alex Corn
0fb2798424 3.48.3 2024-04-18 06:04:25 -04:00
DoctorMcKay
e16136866c Merge pull request #340 from nolddor/patch-1
fix: getUserInventoryContents() make unnecesary calls
2024-04-18 06:04:06 -04:00
Jack Nolddor
cae85433f9 fix: getUserInventoryContents() make unnecesary calls
Steam inventory limits are back to normal there is no reason to just gather 2k items instead 5k max allowed by API
2024-04-18 08:14:14 +02:00
Alex Corn
ba6e29c935 3.48.2 2024-01-18 06:12:30 -05:00
Alex Corn
de95e25867 Fixed steamID not being properly set when cookies have a domain attribute 2024-01-18 06:12:18 -05:00
Alex Corn
e1820efeca 3.48.1 2024-01-18 05:38:41 -05:00
Alex Corn
7cee24199f Fixed login issue caused by differing tokens on different domains 2024-01-18 05:38:06 -05:00
Alex Corn
90eb4d38eb 3.48.0 2023-12-02 21:23:47 -05:00
Alex Corn
b58745c8b7 Added createWebApiKey method 2023-12-02 20:26:52 -05:00
Alex Corn
53154043a3 Use updated AddAuthenticator parameters
The old way still seems to work, but this is what the official mobile app sends now
2023-11-10 20:50:12 -05:00
Alex Corn
6c77c5231c Updated enable and disable_twofactor examples to not use steam-session 2023-11-10 20:49:48 -05:00
Alex Corn
7c564c1453 3.47.1 2023-10-20 00:40:31 -04:00
Alex Corn
b854d6d4d4 Use custom user agent for logins 2023-10-20 00:39:49 -04:00
Alex Corn
67867978f8 Get default user agent string from @doctormckay/user-agents 2023-10-20 00:39:38 -04:00
Alex Corn
e1af63e171 Use steam-session for logins 2023-10-19 22:12:40 -04:00
Alex Corn
e4da22c464 3.47.0 2023-10-01 21:39:33 -04:00
Alex Corn
0f91adf819 Updated xml2js dependency version 2023-10-01 21:39:16 -04:00
Alex Corn
d51c171a48 Rename clanid argument to curatorId 2023-10-01 21:34:04 -04:00
Alex Corn
50276c3a0c Explicitly define which files get published to npm 2023-10-01 21:33:39 -04:00
Alex Corn
b5b50cec50 Ignore dev/ 2023-10-01 21:30:28 -04:00
Alex Corn
cf4b474c70 Added steamID coalescing helper, although currently unused 2023-10-01 21:30:12 -04:00
3urobeat
bf2b4601ee Add user/workshop/curator follow & unfollow support (#320)
* Add follow & unfollow user functions

* Add follow & unfollow to CSteamUser object methods

* Add support for following & unfollowing curators

* Correctly parse for eresult on error

* Use eresultError() helper
2023-10-01 21:22:44 -04:00
Alex Corn
f69519f547 Fixed getUserInventoryContexts not properly returning errors for private inventory/profile
Closes #305
2023-06-27 00:53:55 -04:00
DoctorMcKay
29e18806cc Merge pull request #301 from fjexe/patch-1
Update users.js
2023-06-27 00:43:07 -04:00
DoctorMcKay
c855b505c5 Merge pull request #307 from HerrEurobeat/reenable-primaryGroup-support
Re-enable primaryGroup profile setting
2023-06-27 00:42:46 -04:00
Alex Corn
6cc96b51fa 3.46.1 2023-06-27 00:17:17 -04:00
DoctorMcKay
edf2891800 Merge pull request #314 from HerrEurobeat/fix-sharedfile-owner
Fix resolving vanity returning error
2023-06-27 00:16:17 -04:00
3urobeat
0fc1120fd3 Fix resolving vanity #313 2023-06-26 16:02:15 +02:00
DoctorMcKay
a0aee350cc Update comment 2023-06-26 01:37:08 -04:00
3urobeat
c25cb31e34 Re-enable primaryGroup profile setting 2023-05-14 17:06:56 +02:00
fjexe
2a1d244114 Update users.js 2022-11-04 18:48:35 +03:00
19 changed files with 595 additions and 356 deletions

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
node_modules/*
node_modules/
test.js
dev/
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

View File

@@ -4,9 +4,8 @@
[![license](https://img.shields.io/npm/l/steamcommunity.svg)](https://github.com/DoctorMcKay/node-steamcommunity/blob/master/LICENSE)
[![paypal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=N36YVAT42CZ4G&item_name=node%2dsteamcommunity&currency_code=USD)
This module provides an easy interface for the Steam Community website. This module can be used to simply login to steamcommunity.com for use with other libraries, or to interact with steamcommunity.com.
It supports Steam Guard and CAPTCHAs.
This module provides an easy interface for the Steam Community website. This module can be used to simply login to
steamcommunity.com for use with other libraries, or to interact with steamcommunity.com.
**Have a question about the module or coding in general? *Do not create a GitHub issue.* GitHub issues are for feature
requests and bug reports. Instead, post in the [dedicated forum](https://dev.doctormckay.com/forum/8-node-steamcommunity/).

View File

@@ -1,6 +1,6 @@
module.exports = CEconItem;
function CEconItem(item, description, contextID) {
function CEconItem(item, description, contextID, assetProperties) {
var thing;
for (thing in item) {
if (item.hasOwnProperty(thing)) {
@@ -28,7 +28,7 @@ function CEconItem(item, description, contextID) {
}
for (thing in description) {
if (description.hasOwnProperty(thing)) {
if (description.hasOwnProperty(thing) && !this.hasOwnProperty(thing)) {
this[thing] = description[thing];
}
}
@@ -68,10 +68,26 @@ function CEconItem(item, description, contextID) {
// Restore cache_expiration, if we can (for CS:GO items)
if (this.appid == 730 && this.contextid == 2 && this.owner_descriptions) {
let description = this.owner_descriptions.find(d => d.value && d.value.indexOf('Tradable After ') == 0);
let description = this.owner_descriptions.find((d) => d.value && d.value.indexOf("Tradable/Marketable After ") == 0);
if (description) {
let date = new Date(description.value.substring(15).replace(/[,()]/g, ''));
if (date) {
let date;
const match = description.value.match(/(\d{1,2}) (\w+) @ (\d{1,2}:\d{2})(am|pm)/i);
if (match) {
// New day-first format, e.g. "Tradable/Marketable After 17 Jul @ 3:00am"
const [, day, month, time, meridian] = match;
const now = new Date();
let year = now.getFullYear();
date = new Date(`${day} ${month} ${year} ${time} ${meridian}`);
if (date.getTime() < now.getTime()) {
date = new Date(`${day} ${month} ${year + 1} ${time} ${meridian}`);
}
} else {
// Legacy month-first format, e.g. "Tradable/Marketable After Jul 11, 2025 (2:00:00)"
date = new Date(description.value.substring("Tradable/Marketable After ".length).replace(/[,()]/g, ""));
}
if (date && !isNaN(date.getTime())) {
this.cache_expiration = date.toISOString();
}
}
@@ -86,6 +102,11 @@ function CEconItem(item, description, contextID) {
this.actions = [];
}
// Assign asset_properties if provided
if (assetProperties) {
this.asset_properties = assetProperties;
}
// One wouldn't think that we need this if statement, but apparently v8 has a weird bug/quirk where deleting a
// property results in greatly increased memory usage. Because that makes sense.
if (this.currency) {

View File

@@ -13,7 +13,7 @@ SteamCommunity.prototype.getSteamUser = function(id, callback) {
}
var self = this;
this.httpRequest("http://steamcommunity.com/" + (typeof id === 'string' ? "id/" + id : "profiles/" + id.toString()) + "/?xml=1", function(err, response, body) {
this.httpRequest("https://steamcommunity.com/" + (typeof id === 'string' ? "id/" + id : "profiles/" + id.toString()) + "/?xml=1", function(err, response, body) {
if (err) {
callback(err);
return;
@@ -166,6 +166,14 @@ CSteamUser.prototype.inviteToGroup = function(groupID, callback) {
this._community.inviteUserToGroup(this.steamID, groupID, callback);
};
CSteamUser.prototype.follow = function(callback) {
this._community.followUser(this.steamID, callback);
};
CSteamUser.prototype.unfollow = function(callback) {
this._community.unfollowUser(this.steamID, callback);
};
CSteamUser.prototype.getAliases = function(callback) {
this._community.getUserAliases(this.steamID, callback);
};

View File

@@ -261,7 +261,10 @@ function request(community, url, key, time, tag, params, json, callback) {
var req = {
method: url == 'multiajaxop' ? 'POST' : 'GET',
uri: 'https://steamcommunity.com/mobileconf/' + url,
json: !!json
json: !!json,
headers: {
'user-agent': 'okhttp/4.9.2'
}
};
if (req.method == 'GET') {
@@ -392,6 +395,22 @@ SteamCommunity.prototype.checkConfirmations = function() {
}
};
SteamCommunity.prototype.acknowledgeTradeProtection = function(callback) {
this.httpRequestPost({
uri: 'https://steamcommunity.com//trade/new/acknowledge',
form: {
sessionid: this.getSessionID(),
message: 1
}
}, (err, res, body) => {
if (err) {
return callback && callback(err);
}
callback && callback(null);
}, 'steamcommunity');
}
SteamCommunity.prototype._confirmationCheckerGetKey = function(tag, callback) {
if(this._identitySecret) {
if(tag == 'details') {

View File

@@ -11,17 +11,17 @@ SteamCommunity.prototype.getGroupMembers = function(gid, callback, members, link
if (!link) {
if (typeof gid !== 'string') {
// It's a SteamID object
link = "http://steamcommunity.com/gid/" + gid.toString() + "/memberslistxml/?xml=1";
link = "https://steamcommunity.com/gid/" + gid.toString() + "/memberslistxml/?xml=1";
} else {
try {
var sid = new SteamID(gid);
if (sid.type == SteamID.Type.CLAN && sid.isValid()) {
link = "http://steamcommunity.com/gid/" + sid.getSteamID64() + "/memberslistxml/?xml=1";
link = "https://steamcommunity.com/gid/" + sid.getSteamID64() + "/memberslistxml/?xml=1";
} else {
throw new Error("Doesn't particularly matter what this message is");
}
} catch (e) {
link = "http://steamcommunity.com/groups/" + gid + "/memberslistxml/?xml=1";
link = "https://steamcommunity.com/groups/" + gid + "/memberslistxml/?xml=1";
}
}
}
@@ -175,11 +175,11 @@ SteamCommunity.prototype.postGroupAnnouncement = function(gid, headline, content
"languages[0][headline]": headline,
"languages[0][body]": content
};
if(hidden) {
form.is_hidden = "is_hidden"
}
this.httpRequestPost({
"uri": "https://steamcommunity.com/gid/" + gid.getSteamID64() + "/announcements",
form
@@ -669,7 +669,7 @@ SteamCommunity.prototype.respondToGroupJoinRequests = function(gid, steamIDs, ap
if (typeof gid === 'string') {
gid = new SteamID(gid);
}
var rgAccounts = (!Array.isArray(steamIDs) ? [steamIDs] : steamIDs).map(sid => sid.toString());
this.httpRequestPost({
@@ -730,3 +730,69 @@ SteamCommunity.prototype.respondToAllGroupJoinRequests = function(gid, approve,
}
}, "steamcommunity");
};
/**
* Follows a curator page
* @param {string|number} curatorId - ID of the curator (not a SteamID)
* @param {function} callback - Takes only an Error object/null as the first argument
*/
SteamCommunity.prototype.followCurator = function(curatorId, callback) {
this.httpRequestPost({
"uri": "https://store.steampowered.com/curators/ajaxfollow",
"form": {
"clanid": curatorId,
"sessionid": this.getSessionID(),
"follow": 1
},
"json": true
}, (err, res, body) => {
if (!callback) {
return;
}
if (err) {
callback(err);
return;
}
if (body.success && body.success.success != SteamCommunity.EResult.OK) {
callback(Helpers.eresultError(body.success.success));
return;
}
callback(null);
}, "steamcommunity");
};
/**
* Unfollows a curator page
* @param {string|number} curatorId - ID of the curator (not a SteamID)
* @param {function} callback - Takes only an Error object/null as the first argument
*/
SteamCommunity.prototype.unfollowCurator = function(curatorId, callback) {
this.httpRequestPost({
"uri": "https://store.steampowered.com/curators/ajaxfollow",
"form": {
"clanid": curatorId,
"sessionid": this.getSessionID(),
"follow": 0
},
"json": true
}, (err, res, body) => {
if (!callback) {
return;
}
if (err) {
callback(err);
return;
}
if (body.success && body.success.success != SteamCommunity.EResult.OK) {
callback(Helpers.eresultError(body.success.success));
return;
}
callback(null);
}, "steamcommunity");
};

View File

@@ -1,7 +1,9 @@
const EResult = require('../resources/EResult.js');
const request = require('request');
const SteamID = require('steamid');
const xml2js = require('xml2js');
const EResult = require('../resources/EResult.js');
exports.isSteamID = function(input) {
var keys = Object.keys(input);
if (keys.length != 4) {
@@ -99,10 +101,28 @@ exports.resolveVanityURL = function(url, callback) {
return;
}
let steamID64 = parsed.profile.steamID64;
let vanityURL = parsed.profile.customURL;
let steamID64 = parsed.profile.steamID64[0];
let vanityURL = parsed.profile.customURL[0];
callback(null, {"vanityURL": vanityURL, "steamID": steamID64});
});
});
};
};
/**
* Converts `input` into a SteamID object, if it's a parseable string.
* @param {SteamID|string} input
* @return {SteamID}
*/
exports.steamID = function(input) {
if (exports.isSteamID(input)) {
return input;
}
if (typeof input != 'string') {
throw new Error(`Input SteamID value "${input}" is not a string`);
}
// This will throw if the input is not a well-formed SteamID
return new SteamID(input);
};

View File

@@ -1,3 +1,5 @@
var URL = require('url');
var SteamCommunity = require('../index.js');
SteamCommunity.prototype.httpRequest = function(uri, options, callback, source) {
@@ -19,6 +21,16 @@ SteamCommunity.prototype.httpRequest = function(uri, options, callback, source)
delete this._httpRequestConvenienceMethod;
}
// Add origin header if necessary
// https://github.com/DoctorMcKay/node-steamcommunity/issues/351
if ((options.method || 'GET').toUpperCase() != 'GET') {
options.headers = options.headers || {};
if (!options.headers.origin) {
var parsedUrl = URL.parse(options.url);
options.headers.origin = parsedUrl.protocol + '//' + parsedUrl.host;
}
}
var requestID = ++this._httpRequestID;
source = source || "";

114
components/login.js Normal file
View File

@@ -0,0 +1,114 @@
const {chrome} = require('@doctormckay/user-agents');
const SteamCommunity = require('../index.js');
/**
* @typedef LogOnDetails
* @property {string} accountName
* @property {string} password
* @property {string} [steamguard]
* @property {string} [authCode]
* @property {string} [twoFactorCode]
* @property {boolean} disableMobile
*/
/**
* @typedef LogOnResponse
* @property {string} sessionID
* @property {string[]} cookies
* @property {string} steamguard
* @property {string} [mobileAccessToken]
*/
/**
*
* @param {LogOnDetails} logOnDetails
* @returns {Promise<LogOnResponse>}
* @private
*/
SteamCommunity.prototype._modernLogin = function(logOnDetails) {
return new Promise(async (resolve, reject) => {
if (!isNodeVersionNewEnough()) {
return reject(new Error(`Node.js version is too old! Need >=12.22.0 or later, got ${process.versions.node}.`));
}
if (this._options.request) {
return reject(new Error('SteamCommunity.login() is incompatible with node-steamcommunity v3\'s usage of \'request\'. If you need to specify a custom \'request\' instance (e.g. when using a proxy), use https://www.npmjs.com/package/steam-session directly to log onto Steam.'));
}
// Import this here so we don't cause problems on old Node versions if this code path isn't taken.
const {LoginSession, EAuthTokenPlatformType, EAuthSessionGuardType} = require('steam-session');
let session = new LoginSession(
logOnDetails.disableMobile
? EAuthTokenPlatformType.WebBrowser
: EAuthTokenPlatformType.MobileApp,
{
localAddress: this._options.localAddress,
userAgent: this._options.userAgent || chrome()
}
);
session.on('authenticated', async () => {
try {
let webCookies = await session.getWebCookies();
let sessionIdCookie = webCookies.find(c => c.startsWith('sessionid='));
resolve({
sessionID: sessionIdCookie.split('=')[1].split(';')[0].trim(),
cookies: webCookies,
steamguard: session.steamGuardMachineToken,
mobileAccessToken: logOnDetails.disableMobile ? null : session.accessToken
});
} catch (ex) {
reject(ex);
}
});
session.on('error', (err) => {
reject(err);
});
session.on('timeout', () => {
reject(new Error('Login timed out'));
});
try {
let startResult = await session.startWithCredentials({
accountName: logOnDetails.accountName,
password: logOnDetails.password,
steamGuardMachineToken: logOnDetails.steamguard,
steamGuardCode: logOnDetails.authCode || logOnDetails.twoFactorCode
});
if (startResult.actionRequired) {
// Cannot continue with login, need something from the user
session.cancelLoginAttempt();
let emailMfaAction = startResult.validActions.find(action => action.type == EAuthSessionGuardType.EmailCode);
if (emailMfaAction) {
let err = new Error('SteamGuard');
err.emaildomain = emailMfaAction.detail;
return reject(err);
}
return reject(new Error('SteamGuardMobile'));
}
} catch (ex) {
return reject(ex);
}
});
};
function isNodeVersionNewEnough() {
let [major, minor] = process.versions.node.split('.');
if (major < 12) {
return false;
}
if (major == 12 && minor < 22) {
return false;
}
return true;
}

View File

@@ -106,6 +106,15 @@ SteamCommunity.prototype.editProfile = function(settings, callback) {
values.customURL = settings[i];
break;
case 'primaryGroup':
if(typeof settings[i] === 'object' && settings[i].getSteamID64) {
values.primary_group_steamid = settings[i].getSteamID64();
} else {
values.primary_group_steamid = new SteamID(settings[i]).getSteamID64();
}
break;
// These don't work right now
/*
case 'background':
@@ -117,15 +126,6 @@ SteamCommunity.prototype.editProfile = function(settings, callback) {
// Currently, game badges aren't supported
values.favorite_badge_badgeid = settings[i];
break;
case 'primaryGroup':
if(typeof settings[i] === 'object' && settings[i].getSteamID64) {
values.primary_group_steamid = settings[i].getSteamID64();
} else {
values.primary_group_steamid = new SteamID(settings[i]).getSteamID64();
}
break;
*/
// TODO: profile showcases
}

View File

@@ -20,10 +20,10 @@ SteamCommunity.prototype.enableTwoFactor = function(callback) {
// TODO: Send this as protobuf to more closely mimic official app behavior
form: {
steamid: this.steamID.getSteamID64(),
authenticator_time: Math.floor(Date.now() / 1000),
authenticator_type: ETwoFactorTokenType.ValveMobileApp,
device_identifier: SteamTotp.getDeviceID(this.steamID),
sms_phone_id: '1'
sms_phone_id: '1',
version: 2
},
json: true
}, (err, response, body) => {

View File

@@ -296,6 +296,66 @@ SteamCommunity.prototype.inviteUserToGroup = function(userID, groupID, callback)
}, "steamcommunity");
};
SteamCommunity.prototype.followUser = function(userID, callback) {
if(typeof userID === 'string') {
userID = new SteamID(userID);
}
this.httpRequestPost({
"uri": `https://steamcommunity.com/profiles/${userID.toString()}/followuser/`,
"form": {
"sessionid": this.getSessionID(),
},
"json": true
}, function(err, response, body) {
if (!callback) {
return;
}
if (err) {
callback(err);
return;
}
if (body.success && body.success != SteamCommunity.EResult.OK) {
callback(Helpers.eresultError(body.success));
return;
}
callback(null);
}, "steamcommunity");
};
SteamCommunity.prototype.unfollowUser = function(userID, callback) {
if(typeof userID === 'string') {
userID = new SteamID(userID);
}
this.httpRequestPost({
"uri": `https://steamcommunity.com/profiles/${userID.toString()}/unfollowuser/`,
"form": {
"sessionid": this.getSessionID(),
},
"json": true
}, function(err, response, body) {
if (!callback) {
return;
}
if (err) {
callback(err);
return;
}
if (body.success && body.success != SteamCommunity.EResult.OK) {
callback(Helpers.eresultError(body.success));
return;
}
callback(null);
}, "steamcommunity");
};
SteamCommunity.prototype.getUserAliases = function(userID, callback) {
if (typeof userID === 'string') {
userID = new SteamID(userID);
@@ -385,18 +445,7 @@ SteamCommunity.prototype.getUserInventoryContexts = function(userID, callback) {
var match = body.match(/var g_rgAppContextData = ([^\n]+);\r?\n/);
if (!match) {
var errorMessage = "Malformed response";
if(body.match(/0 items in their inventory\./)){
callback(null, {});
return;
}else if(body.match(/inventory is currently private\./)){
errorMessage = "Private inventory";
}else if(body.match(/profile\_private\_info/)){
errorMessage = "Private profile";
}
callback(new Error(errorMessage));
callback(new Error('Malformed response'));
return;
}
@@ -408,6 +457,21 @@ SteamCommunity.prototype.getUserInventoryContexts = function(userID, callback) {
return;
}
if (Object.keys(data).length == 0) {
if (body.match(/inventory is currently private\./)) {
callback(new Error('Private inventory'));
return;
}
if (body.match(/profile_private_info/)) {
callback(new Error('Private profile'));
return;
}
// If they truly have no items in their inventory, Steam will send g_rgAppContextData as [] instead of {}.
data = {};
}
callback(null, data);
}, "steamcommunity");
};
@@ -472,7 +536,7 @@ SteamCommunity.prototype.getUserInventory = function(userID, appID, contextID, t
continue;
}
currency.push(new CEconItem(body.rgInventory[i], body.rgDescriptions, contextID));
currency.push(new CEconItem(body.rgCurrency[i], body.rgDescriptions, contextID));
}
if (body.more) {
@@ -526,7 +590,7 @@ SteamCommunity.prototype.getUserInventoryContents = function(userID, appID, cont
},
"qs": {
"l": language, // Default language
"count": 2000, // Max items per 'page'
"count": 1000, // Max items per 'page'
"start_assetid": start
},
"json": true
@@ -565,6 +629,13 @@ SteamCommunity.prototype.getUserInventoryContents = function(userID, appID, cont
return;
}
if (appID == 730 && body && body.success && !body.assets) {
// CS inventory has no visible items. We need a special case for this because Valve is incapable of
// doing anything not dumb.
callback(null, [], [], body.total_inventory_count);
return;
}
if (!body || !body.success || !body.assets || !body.descriptions) {
if (body) {
// Dunno if the error/Error property even exists on this new endpoint
@@ -576,12 +647,21 @@ SteamCommunity.prototype.getUserInventoryContents = function(userID, appID, cont
return;
}
// Build asset_properties lookup by assetid
var assetPropertiesLookup = {};
if (body.asset_properties) {
for (var j = 0; j < body.asset_properties.length; j++) {
assetPropertiesLookup[body.asset_properties[j].assetid] = body.asset_properties[j].asset_properties;
}
}
for (var i = 0; i < body.assets.length; i++) {
var description = getDescription(body.descriptions, body.assets[i].classid, body.assets[i].instanceid);
if (!tradableOnly || (description && description.tradable)) {
body.assets[i].pos = pos++;
(body.assets[i].currencyid ? currency : inventory).push(new CEconItem(body.assets[i], description, contextID));
var assetProperties = assetPropertiesLookup[body.assets[i].assetid] || null;
(body.assets[i].currencyid ? currency : inventory).push(new CEconItem(body.assets[i], description, contextID, assetProperties));
}
}

View File

@@ -1,49 +1,152 @@
var SteamCommunity = require('../index.js');
const SteamCommunity = require('../index.js');
const Helpers = require('./helpers.js');
SteamCommunity.prototype.getWebApiKey = function(domain, callback) {
var self = this;
/**
* Retrieves your account's Steam Web API key, if you already have one. If you don't yet have one, this will fail.
* To create a Web API key, use `createWebApiKey()`.
*
* @param {null|function} unused - No longer used, kept for backward compatibility. You can omit this parameter and pass
* your callback directly as the first parameter if you want.
* @param {function} callback
*/
SteamCommunity.prototype.getWebApiKey = function(unused, callback) {
if (typeof unused == 'function') {
callback = unused;
}
this.httpRequest({
"uri": "https://steamcommunity.com/dev/apikey?l=english",
"followRedirect": false
}, function(err, response, body) {
uri: 'https://steamcommunity.com/dev/apikey?l=english',
followRedirect: false
}, (err, response, body) => {
if (err) {
callback(err);
return;
}
if(body.match(/<h2>Access Denied<\/h2>/)) {
return callback(new Error("Access Denied"));
if (body.match(/You must have a validated email address to create a Steam Web API key./)) {
return callback(new Error('You must have a validated email address to create a Steam Web API key.'));
}
if(body.match(/You must have a validated email address to create a Steam Web API key./)) {
return callback(new Error("You must have a validated email address to create a Steam Web API key."));
if (body.match(/Your account requires (<a [^>]+>)?Steam Guard Mobile Authenticator/)) {
return callback(new Error('Steam Guard Mobile Authenticator required to create a Steam Web API key'));
}
var match = body.match(/<p>Key: ([0-9A-F]+)<\/p>/);
if(match) {
if (body.match(/<h2>Access Denied<\/h2>/)) {
return callback(new Error('Access Denied'));
}
let match = body.match(/<p>Key: ([0-9A-F]+)<\/p>/);
if (match) {
// We already have an API key registered
callback(null, match[1]);
} else {
// We need to register a new API key
self.httpRequestPost('https://steamcommunity.com/dev/registerkey?l=english', {
"form": {
"domain": domain,
"agreeToTerms": "agreed",
"sessionid": self.getSessionID(),
"Submit": "Register"
}
}, function(err, response, body) {
if (err) {
callback(err);
callback(new Error('No API key created for this account'));
}
}, "steamcommunity");
};
/**
* @typedef CreateApiKeyOptions
* @property {string} domain - The domain to associate with your API key
* @property {string} [requestID] - If finalizing an existing create request, include the request ID
* @property {string|Buffer} [identitySecret] - If you pass your identity_secret here, then steamcommunity will
* internally handle accepting any confirmations.
*/
/**
* @typedef CreateApiKeyResponse
* @property {boolean} confirmationRequired
* @property {string} [apiKey] - If creating your API key succeeded, this is the new key
* @property {CreateApiKeyOptions} [finalizeOptions] - If confirmation is required to create a key, then accept the
* confirmation, then call createWebApiKey again and pass this whole object for the `options` parameter.
*/
/**
* @callback createWebApiKeyCallback
* @param {Error|null} err
* @param {CreateApiKeyResponse} [result]
*/
/**
* Starts the process to create a Steam Web API key. When the callback is fired, you will need to approve a mobile
* confirmation in your app or using getConfirmations().
*
* @param {CreateApiKeyOptions} options
* @param {createWebApiKeyCallback} callback
*/
SteamCommunity.prototype.createWebApiKey = function(options, callback) {
if (!options.domain) {
callback(new Error('Passing a domain is required to register an API key'));
return;
}
this.httpRequestPost({
uri: 'https://steamcommunity.com/dev/requestkey',
form: {
domain: options.domain,
request_id: options.requestID || '0',
sessionid: this.getSessionID(),
agreeToTerms: 'true'
},
json: true
}, (err, res, body) => {
if (err) {
callback(err);
return;
}
// body.requires_confirmation is 1/0, but the Steam website doesn't check this value and instead only checks the
// value of `success`. So let's just do that.
// This is a mess. I'm glad we have promises and await now.
switch (body.success) {
case SteamCommunity.EResult.OK:
if (body.api_key) {
callback(null, {confirmationRequired: false, apiKey: body.api_key});
return;
}
self.getWebApiKey(domain, callback);
}, "steamcommunity");
// It's not been observed that we get result OK without api_key included, but the Steam website doesn't
// use this value so let's be safe just in case it disappears in the future.
this.getWebApiKey((err, key) => {
if (err) {
callback(err);
return;
}
callback(null, {confirmationRequired: false, apiKey: key});
});
return;
case SteamCommunity.EResult.Pending:
let finalizeOptions = {
domain: options.domain,
requestID: body.request_id || options.requestID
}
if (options.identitySecret) {
this.acceptConfirmationForObject(options.identitySecret, finalizeOptions.requestID, (err) => {
if (err) {
callback(err);
} else {
this.createWebApiKey(finalizeOptions, callback);
}
});
return;
}
callback(null, {
confirmationRequired: true,
finalizeOptions: finalizeOptions
});
return;
default:
callback(Helpers.eresultError(body.success));
}
}, "steamcommunity");
});
};
/**

1
examples/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
twofactor_*.json

View File

@@ -56,9 +56,9 @@ async function main() {
let codeAction = startResult.validActions.find(action => codeActionTypes.includes(action.type));
if (codeAction) {
if (codeAction.type == SteamSession.EAuthSessionGuardType.EmailCode) {
// We wouldn't expect this to happen since mobile confirmations are only possible with 2FA enabled, but just in case...
console.log(`A code has been sent to your email address at ${codeAction.detail}.`);
} else {
// We wouldn't expect this to happen since we're trying to enable 2FA, but just in case...
console.log('You need to provide a Steam Guard Mobile Authenticator code.');
}

View File

@@ -1,7 +1,7 @@
// If you aren't running this script inside of the repository, replace the following line with:
// const SteamCommunity = require('steamcommunity');
const SteamCommunity = require('../index.js');
const SteamSession = require('steam-session');
const SteamTotp = require('steam-totp');
const ReadLine = require('readline');
let g_AbortPromptFunc = null;
@@ -13,69 +13,32 @@ async function main() {
let accountName = await promptAsync('Username: ');
let password = await promptAsync('Password (hidden): ', true);
// Create a LoginSession for us to use to attempt to log into steam
let session = new SteamSession.LoginSession(SteamSession.EAuthTokenPlatformType.MobileApp);
attemptLogin(accountName, password);
}
// Go ahead and attach our event handlers before we do anything else.
session.on('authenticated', async () => {
abortPrompt();
function attemptLogin(accountName, password, twoFactorCode) {
community.login({
accountName,
password,
twoFactorCode,
disableMobile: false
}, async (err) => {
if (err && err.message == 'SteamGuardMobile') {
let code = await promptAsync('Steam Guard App Code OR Shared Secret: ');
if (code.length > 5) {
// If we were provided a shared secret, turn it into a code.
code = SteamTotp.getAuthCode(code);
}
attemptLogin(accountName, password, code);
return;
}
let accessToken = session.accessToken;
let cookies = await session.getWebCookies();
community.setCookies(cookies);
community.setMobileAppAccessToken(accessToken);
// Enabling or disabling 2FA is presently the only action in node-steamcommunity which requires an access token.
// In all other cases, using `community.setCookies(cookies)` is all you need to do in order to be logged in,
// although there's never any harm in setting a mobile app access token.
if (err) {
throw err;
}
doRevoke();
});
session.on('timeout', () => {
abortPrompt();
console.log('This login attempt has timed out.');
});
session.on('error', (err) => {
abortPrompt();
// This should ordinarily not happen. This only happens in case there's some kind of unexpected error while
// polling, e.g. the network connection goes down or Steam chokes on something.
console.log(`ERROR: This login attempt has failed! ${err.message}`);
});
// Start our login attempt
let startResult = await session.startWithCredentials({accountName, password});
if (startResult.actionRequired) {
// Some Steam Guard action is required. We only care about email and device codes; in theory an
// EmailConfirmation and/or DeviceConfirmation action could be possible, but we're just going to ignore those.
// If the user does receive a confirmation and accepts it, LoginSession will detect and handle that automatically.
// The only consequence of ignoring it here is that we don't print a message to the user indicating that they
// could accept an email or device confirmation.
let codeActionTypes = [SteamSession.EAuthSessionGuardType.EmailCode, SteamSession.EAuthSessionGuardType.DeviceCode];
let codeAction = startResult.validActions.find(action => codeActionTypes.includes(action.type));
if (codeAction) {
if (codeAction.type == SteamSession.EAuthSessionGuardType.EmailCode) {
// We wouldn't expect this to happen since we're trying to disable 2FA, but just in case...
console.log(`A code has been sent to your email address at ${codeAction.detail}.`);
} else {
console.log('You need to provide a Steam Guard Mobile Authenticator code.');
}
let code = await promptAsync('Code: ');
if (code) {
await session.submitSteamGuardCode(code);
}
// If we fall through here without submitting a Steam Guard code, that means one of two things:
// 1. The user pressed enter without providing a code, in which case the script will simply exit
// 2. The user approved a device/email confirmation, in which case 'authenticated' was emitted and the prompt was canceled
}
}
}
async function doRevoke() {

View File

@@ -1,7 +1,6 @@
// If you aren't running this script inside of the repository, replace the following line with:
// const SteamCommunity = require('steamcommunity');
const SteamCommunity = require('../index.js');
const SteamSession = require('steam-session');
const ReadLine = require('readline');
const FS = require('fs');
@@ -16,69 +15,28 @@ async function main() {
let accountName = await promptAsync('Username: ');
let password = await promptAsync('Password (hidden): ', true);
// Create a LoginSession for us to use to attempt to log into steam
let session = new SteamSession.LoginSession(SteamSession.EAuthTokenPlatformType.MobileApp);
attemptLogin(accountName, password);
}
// Go ahead and attach our event handlers before we do anything else.
session.on('authenticated', async () => {
abortPrompt();
function attemptLogin(accountName, password, authCode) {
community.login({
accountName,
password,
authCode,
disableMobile: false
}, async (err) => {
if (err && err.message == 'SteamGuard') {
let code = await promptAsync('Steam Guard Email Code: ');
attemptLogin(accountName, password, code);
return;
}
let accessToken = session.accessToken;
let cookies = await session.getWebCookies();
community.setCookies(cookies);
community.setMobileAppAccessToken(accessToken);
// Enabling or disabling 2FA is presently the only action in node-steamcommunity which requires an access token.
// In all other cases, using `community.setCookies(cookies)` is all you need to do in order to be logged in,
// although there's never any harm in setting a mobile app access token.
if (err) {
throw err;
}
doSetup();
});
session.on('timeout', () => {
abortPrompt();
console.log('This login attempt has timed out.');
});
session.on('error', (err) => {
abortPrompt();
// This should ordinarily not happen. This only happens in case there's some kind of unexpected error while
// polling, e.g. the network connection goes down or Steam chokes on something.
console.log(`ERROR: This login attempt has failed! ${err.message}`);
});
// Start our login attempt
let startResult = await session.startWithCredentials({accountName, password});
if (startResult.actionRequired) {
// Some Steam Guard action is required. We only care about email and device codes; in theory an
// EmailConfirmation and/or DeviceConfirmation action could be possible, but we're just going to ignore those.
// If the user does receive a confirmation and accepts it, LoginSession will detect and handle that automatically.
// The only consequence of ignoring it here is that we don't print a message to the user indicating that they
// could accept an email or device confirmation.
let codeActionTypes = [SteamSession.EAuthSessionGuardType.EmailCode, SteamSession.EAuthSessionGuardType.DeviceCode];
let codeAction = startResult.validActions.find(action => codeActionTypes.includes(action.type));
if (codeAction) {
if (codeAction.type == SteamSession.EAuthSessionGuardType.EmailCode) {
console.log(`A code has been sent to your email address at ${codeAction.detail}.`);
} else {
// We wouldn't expect this to happen since we're trying to enable 2FA, but just in case...
console.log('You need to provide a Steam Guard Mobile Authenticator code.');
}
let code = await promptAsync('Code: ');
if (code) {
await session.submitSteamGuardCode(code);
}
// If we fall through here without submitting a Steam Guard code, that means one of two things:
// 1. The user pressed enter without providing a code, in which case the script will simply exit
// 2. The user approved a device/email confirmation, in which case 'authenticated' was emitted and the prompt was canceled
}
}
}
function doSetup() {
@@ -118,10 +76,13 @@ function doSetup() {
async function promptActivationCode(response) {
if (response.phone_number_hint) {
console.log(`A code has been sent to your phone ending in ${response.phone_number_hint}.`);
console.log(`An activation code has been sent to your phone ending in ${response.phone_number_hint}.`);
} else if (response.confirm_type == 3) {
// Exact meaning of confirm_type is unknown, but 3 appears to be email code
console.log('An activation code has been sent to your email.');
}
let smsCode = await promptAsync('SMS Code: ');
let smsCode = await promptAsync('Activation Code: ');
community.finalizeTwoFactor(response.shared_secret, smsCode, (err) => {
if (err) {
if (err.message == 'Invalid activation code') {

178
index.js
View File

@@ -1,12 +1,9 @@
const hex2b64 = require('node-bignumber').hex2b64;
const {chrome} = require('@doctormckay/user-agents');
const Request = require('request');
const RSA = require('node-bignumber').Key;
const SteamID = require('steamid');
const Helpers = require('./components/helpers.js');
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";
require('util').inherits(SteamCommunity, require('events').EventEmitter);
module.exports = SteamCommunity;
@@ -31,7 +28,7 @@ function SteamCommunity(options) {
"timeout": options.timeout || 50000,
"gzip": true,
"headers": {
"User-Agent": options.userAgent || USER_AGENT
"User-Agent": options.userAgent || chrome()
}
};
@@ -61,158 +58,22 @@ SteamCommunity.prototype.login = function(details, callback) {
throw new Error("Missing either accountName or password to login; both are needed");
}
if (details.steamguard) {
var parts = details.steamguard.split('||');
this._setCookie(Request.cookie('steamMachineAuth' + parts[0] + '=' + encodeURIComponent(parts[1])), true);
}
var disableMobile = typeof details.disableMobile == 'undefined' ? true : details.disableMobile;
var self = this;
// Delete the cache
delete self._profileURL;
delete this._profileURL;
// headers required to convince steam that we're logging in from a mobile device so that we can get the oAuth data
var mobileHeaders = {};
if (!disableMobile) {
mobileHeaders = {
"X-Requested-With": "com.valvesoftware.android.steam.community",
"Referer": "https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client",
"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",
"Accept": "text/javascript, text/html, application/xml, text/xml, */*"
};
// default disableMobile to true
let logOnOptions = Object.assign({}, details);
logOnOptions.disableMobile = details.disableMobile !== false;
this._setCookie(Request.cookie("mobileClientVersion=0 (2.1.3)"));
this._setCookie(Request.cookie("mobileClient=android"));
} else {
mobileHeaders = {"Referer": "https://steamcommunity.com/login"};
}
this._modernLogin(logOnOptions).then(({sessionID, cookies, steamguard, mobileAccessToken}) => {
this.setCookies(cookies);
this.httpRequestPost("https://steamcommunity.com/login/getrsakey/", {
"form": {"username": details.accountName},
"headers": mobileHeaders,
"json": true
}, function(err, response, body) {
// Remove the mobile cookies
if (err) {
deleteMobileCookies();
callback(err);
return;
if (mobileAccessToken) {
this.setMobileAppAccessToken(mobileAccessToken);
}
if (!body.publickey_mod || !body.publickey_exp) {
deleteMobileCookies();
callback(new Error("Invalid RSA key received"));
return;
}
var key = new RSA();
key.setPublic(body.publickey_mod, body.publickey_exp);
var formObj = {
"captcha_text": details.captcha || "",
"captchagid": self._captchaGid,
"emailauth": details.authCode || "",
"emailsteamid": "",
"password": hex2b64(key.encrypt(details.password)),
"remember_login": "true",
"rsatimestamp": body.timestamp,
"twofactorcode": details.twoFactorCode || "",
"username": details.accountName,
"loginfriendlyname": "",
"donotcache": Date.now()
};
if (!disableMobile) {
formObj.oauth_client_id = "DE45CD61";
formObj.oauth_scope = "read_profile write_profile read_client write_client";
formObj.loginfriendlyname = "#login_emailauth_friendlyname_mobile";
}
self.httpRequestPost({
"uri": "https://steamcommunity.com/login/dologin/",
"json": true,
"form": formObj,
"headers": mobileHeaders
}, function(err, response, body) {
deleteMobileCookies();
if (err) {
callback(err);
return;
}
var error;
if (!body.success && body.emailauth_needed) {
// Steam Guard (email)
error = new Error("SteamGuard");
error.emaildomain = body.emaildomain;
callback(error);
} else if (!body.success && body.requires_twofactor) {
// Steam Guard (app)
callback(new Error("SteamGuardMobile"));
} else if (!body.success && body.captcha_needed && body.message.match(/Please verify your humanity/)) {
error = new Error("CAPTCHA");
error.captchaurl = "https://steamcommunity.com/login/rendercaptcha/?gid=" + body.captcha_gid;
self._captchaGid = body.captcha_gid;
callback(error);
} else if (!body.success) {
callback(new Error(body.message || "Unknown error"));
} else {
var sessionID = generateSessionID();
var oAuth = {};
self._setCookie(Request.cookie('sessionid=' + sessionID));
var cookies = self._jar.getCookieString("https://steamcommunity.com").split(';').map(function(cookie) {
return cookie.trim();
});
if (!disableMobile && body.oauth) {
oAuth = JSON.parse(body.oauth);
self.steamID = new SteamID(oAuth.steamid);
self.oAuthToken = oAuth.oauth_token;
} else {
for(var i = 0; i < cookies.length; i++) {
var parts = cookies[i].split('=');
if(parts[0] == 'steamLogin') {
self.steamID = new SteamID(decodeURIComponent(parts[1]).split('||')[0])
break;
}
}
self.oAuthToken = null;
}
// Find the Steam Guard cookie
var steamguard = null;
for (var i = 0; i < cookies.length; i++) {
var parts = cookies[i].split('=');
if(parts[0] == 'steamMachineAuth' + self.steamID) {
steamguard = self.steamID.toString() + '||' + decodeURIComponent(parts[1]);
break;
}
}
self.setCookies(cookies);
callback(null, sessionID, cookies, steamguard, disableMobile ? null : oAuth.oauth_token);
}
}, "steamcommunity");
}, "steamcommunity");
function deleteMobileCookies() {
var cookie = Request.cookie('mobileClientVersion=');
cookie.expires = new Date(0);
self._setCookie(cookie);
cookie = Request.cookie('mobileClient=');
cookie.expires = new Date(0);
self._setCookie(cookie);
}
callback(null, sessionID, cookies, steamguard, null);
}).catch(err => callback(err));
};
/**
@@ -293,16 +154,20 @@ SteamCommunity.prototype._setCookie = function(cookie, secure) {
var protocol = secure ? "https" : "http";
cookie.secure = !!secure;
this._jar.setCookie(cookie.clone(), protocol + "://steamcommunity.com");
this._jar.setCookie(cookie.clone(), protocol + "://store.steampowered.com");
this._jar.setCookie(cookie.clone(), protocol + "://help.steampowered.com");
if (cookie.domain) {
this._jar.setCookie(cookie.clone(), protocol + '://' + cookie.domain);
} else {
this._jar.setCookie(cookie.clone(), protocol + "://steamcommunity.com");
this._jar.setCookie(cookie.clone(), protocol + "://store.steampowered.com");
this._jar.setCookie(cookie.clone(), protocol + "://help.steampowered.com");
}
};
SteamCommunity.prototype.setCookies = function(cookies) {
cookies.forEach((cookie) => {
var cookieName = cookie.match(/(.+)=/)[1];
var cookieName = cookie.trim().split('=')[0];
if (cookieName == 'steamLogin' || cookieName == 'steamLoginSecure') {
this.steamID = new SteamID(cookie.match(/=(\d+)/)[1]);
this.steamID = new SteamID(cookie.match(/steamLogin(Secure)?=(\d+)/)[2]);
}
this._setCookie(Request.cookie(cookie), !!(cookieName.match(/^steamMachineAuth/) || cookieName.match(/Secure$/)));
@@ -576,6 +441,7 @@ SteamCommunity.prototype.getFriendsList = function(callback) {
});
};
require('./components/login.js');
require('./components/http.js');
require('./components/chat.js');
require('./components/profile.js');

View File

@@ -1,7 +1,14 @@
{
"name": "steamcommunity",
"version": "3.46.0",
"version": "3.50.3",
"description": "Provides an interface for logging into and interacting with the Steam Community website",
"files": [
"/classes",
"/components",
"/examples",
"/resources",
"/index.js"
],
"keywords": [
"steam",
"steam community"
@@ -21,17 +28,15 @@
"url": "https://github.com/DoctorMcKay/node-steamcommunity.git"
},
"dependencies": {
"@doctormckay/user-agents": "^1.0.0",
"async": "^2.6.3",
"cheerio": "0.22.0",
"image-size": "^0.8.2",
"node-bignumber": "^1.2.1",
"request": "^2.88.0",
"steam-session": "^1.9.1",
"steam-totp": "^1.5.0",
"steamid": "^1.1.3",
"xml2js": "^0.4.22"
},
"devDependencies": {
"steam-session": "^1.2.3"
"xml2js": "^0.6.2"
},
"engines": {
"node": ">=4.0.0"