Compare commits

...

86 Commits

Author SHA1 Message Date
Alexander Corn
0bb2cb6137 3.3.2 2015-07-29 22:29:23 -04:00
Alexander Corn
c9538137d5 Fixed crashes when using various CSteamUser methods 2015-07-29 22:29:14 -04:00
Alexander Corn
df05fd04c4 3.3.1 2015-07-29 22:22:57 -04:00
Alexander Corn
dee52bf7e2 Fixed crashes when using various class methods 2015-07-29 22:22:43 -04:00
Alexander Corn
6d455e8797 3.3.0 2015-07-27 22:56:42 -04:00
Alexander Corn
a0b776ca8b Added setupProfile method 2015-07-27 22:55:25 -04:00
Alexander Corn
3f0db21e02 3.2.1 2015-07-25 01:58:00 -04:00
Alexander Corn
6798b73a17 Made profile callbacks optional 2015-07-25 01:57:53 -04:00
Alexander Corn
b98451a4b6 3.2.0 2015-07-25 01:55:45 -04:00
Alexander Corn
af2ba3f56b Added editProfile method 2015-07-25 01:55:33 -04:00
Alexander Corn
9c2662ae16 Updated profileSettings to accept only some options 2015-07-25 01:39:19 -04:00
Alexander Corn
9ee49d4f15 Added profileSettings method 2015-07-25 01:24:28 -04:00
Alexander Corn
911ae86379 3.1.1 2015-07-22 11:59:43 -04:00
Alexander Corn
a12e8cb67c Added 50-second HTTP timeout 2015-07-22 11:59:18 -04:00
Alexander Corn
edd95cc93f 3.1.0 2015-07-17 22:57:51 -04:00
Alexander Corn
4f1f265c4d Added support for app-based Steam Guard 2015-07-17 22:57:40 -04:00
Alexander Corn
80c0c3ebbc 3.0.0 2015-07-17 22:26:49 -04:00
Alexander Corn
a1ef4b5646 Added captcha support 2015-07-17 22:26:29 -04:00
Alexander Corn
06f7f10dfe All callbacks now consistently return Error objects instead of strings 2015-07-17 22:23:20 -04:00
Alexander Corn
484c049940 Fixed error when SteamGuard is needed not being 'SteamGuard' 2015-07-17 22:07:16 -04:00
Alexander Corn
36038daa1b 2.6.0 2015-07-17 21:21:59 -04:00
Alexander Corn
12cffdd62c Added Family View status to loggedIn method callback 2015-07-17 21:19:43 -04:00
Alexander Corn
eaacef66bb Added loggedIn method 2015-07-17 21:10:08 -04:00
Alexander Corn
0ef652cbac 2.5.2 2015-07-10 16:24:59 -04:00
Alexander Corn
608377277c Sort market results by price to try to avoid duplicates 2015-07-10 16:24:42 -04:00
Alexander Corn
bcaa740b54 2.5.1 2015-07-10 16:01:10 -04:00
Alexander Corn
2674287b43 Make sure everything is in English 2015-07-10 16:00:56 -04:00
Alexander Corn
8b6bed5527 2.5.0 2015-07-10 15:46:42 -04:00
Alexander Corn
6def665b64 Added SteamCommunity#marketSearch 2015-07-10 15:46:29 -04:00
Alexander Corn
4f618c0a27 2.4.0 2015-06-29 16:38:36 -04:00
Alexander Corn
19fe951d96 Added ability to spoof UI mode 2015-06-29 16:38:24 -04:00
Alexander Corn
a348112ccb 2.3.0 2015-06-28 22:18:48 -04:00
Alexander Corn
dff2727f85 Don't fire callback if not provided 2015-06-28 22:16:49 -04:00
Alexander Corn
1fd12dd4d0 Added CMarketItem 2015-06-28 20:19:42 -04:00
Alexander Corn
31093da1a8 Use better dependency semver 2015-06-28 19:40:00 -04:00
Alexander Corn
1e609524e8 2.2.1 2015-06-24 13:31:17 -04:00
Alexander Corn
2a758fc180 Remember Steam login so that cookies don't expire if logged in elsewhere 2015-06-24 13:31:01 -04:00
Alexander Corn
eb2081c325 2.2.0 2015-06-18 00:57:23 -04:00
Alexander Corn
c60d4942e0 Removed useless timestamp parameter from chatMessage event 2015-06-18 00:41:55 -04:00
Alexander Corn
1aa42b89f7 Added public static CSteamUser.getAvatarURL method 2015-06-18 00:41:26 -04:00
Alexander Corn
e01d05c140 Added PersonaStateFlag enum 2015-06-18 00:36:26 -04:00
Alexander Corn
8ec0ef84c2 Added PersonaState enum 2015-06-18 00:33:34 -04:00
Alexander Corn
0e5929df24 Lowered chat poll interval to 500ms 2015-06-18 00:24:54 -04:00
Alexander Corn
74bf2dcfca Added webchat 2015-06-18 00:22:05 -04:00
Alexander Corn
e8634e17ca 2.1.0 2015-06-09 14:45:34 -04:00
Alexander Corn
2a2947344f Export request 2015-06-09 14:45:07 -04:00
Alexander Corn
e789d07833 2.0.0 2015-05-30 23:53:59 -04:00
Alexander Corn
88059596b3 Use a string for the steamguard value instead of an object 2015-05-30 23:45:46 -04:00
Alexander Corn
399cc5ee84 1.0.8 2015-05-29 01:03:22 -04:00
Alexander Corn
a24bb9d4ad Fixed API key registration not working 2015-05-29 01:03:07 -04:00
Alexander Corn
81eb26b30d 1.0.7 2015-05-25 13:43:38 -04:00
Alexander Corn
0c95e75e39 Added getNotifications method 2015-05-25 13:37:01 -04:00
Alexander Corn
2eaa5b057d Added resetItemNotifications method 2015-05-25 13:20:47 -04:00
Alexander Corn
d5592246cf 1.0.6 2015-05-16 00:44:42 -04:00
Alexander Corn
22ab86434a Fixed repository URL 2015-05-16 00:44:33 -04:00
Alexander Corn
d367ceb2a6 1.0.5 2015-05-11 15:56:57 -04:00
Alexander Corn
5ab5a6d401 Made callback optional for parentalUnlock 2015-05-11 15:56:41 -04:00
Alexander Corn
a88a39c62c 1.0.4 2015-05-11 15:48:13 -04:00
Alexander Corn
5f4f4a03a4 Added parentalUnlock method 2015-05-11 15:48:00 -04:00
Alexander Corn
079db4b7bf 1.0.3 2015-05-11 01:09:58 -04:00
Alexander Corn
22ba30f5da Added getWebApiKey method 2015-05-11 01:07:14 -04:00
Alexander Corn
8ca763d9b9 1.0.2 2015-04-26 01:33:29 -04:00
Alexander Corn
eb88ace3d7 Added removeFriend, blockCommunication, and unblockCommunication 2015-04-26 01:16:27 -04:00
Alexander Corn
4138d1c14a Added the beginning of CSteamUser 2015-04-25 14:46:25 -04:00
Alexander Corn
4c0cd4dc8b Removed rogue console.log 2015-04-25 14:07:45 -04:00
Alexander Corn
8bad7dd09f Fixed empty string error when Steam Guard is needed 2015-04-25 14:06:46 -04:00
Alexander Corn
3402acb33a 1.0.1 2015-01-30 02:46:24 -05:00
Alexander Corn
00426a6aea Updated description 2015-01-30 02:46:03 -05:00
Alexander Corn
116c57e6ff Fixed readme 2014-12-17 04:12:26 -05:00
Alexander Corn
193d77c3d1 1.0.0 2014-12-17 04:10:42 -05:00
Alexander Corn
6014ce1567 Updated readme 2014-12-17 04:09:47 -05:00
Alexander Corn
8e8ce2aa89 Added CSteamGroup.leave method 2014-12-17 03:07:59 -05:00
Alexander Corn
0cb5eef1f8 Added _myProfile helper to make calls to the user's profile URL 2014-12-17 03:07:49 -05:00
Alexander Corn
7f2a287c56 Added CSteamGroup.join method 2014-12-17 02:49:51 -05:00
Alexander Corn
7643d2efad Added CSteamGroup.kick method 2014-12-17 02:42:15 -05:00
Alexander Corn
d257108500 Added CSteamGroup.setPlayerOfTheWeek method 2014-12-17 02:39:53 -05:00
Alexander Corn
b0b8dbbabf Added scheduleEvent method 2014-12-17 02:29:58 -05:00
Alexander Corn
b1e31b32fe Moved checking for Steam Community errors to main SteamCommunity 2014-12-17 02:04:24 -05:00
Alexander Corn
0f16f11668 Added postAnnouncement method to CSteamGroup 2014-12-17 01:59:21 -05:00
Alexander Corn
e6789b1021 Added CSteamGroup 2014-12-17 01:48:17 -05:00
Alexander Corn
218d0dc7da Added xml2js dependency 2014-12-17 01:48:07 -05:00
Alexander Corn
5ca5bc30ac Use SteamID class for SteamIDs 2014-12-17 00:55:43 -05:00
Alexander Corn
7d1c641967 Added steamid dependency 2014-12-17 00:50:15 -05:00
Alexander Corn
90593b2dc0 Ignore test.js 2014-12-17 00:48:52 -05:00
Alexander Corn
3d3c899f9d Started shift to more versatile module 2014-12-17 00:48:19 -05:00
Alexander Corn
037ac1a9d7 Bumped required request version 2014-12-17 00:47:54 -05:00
10 changed files with 1479 additions and 122 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
node_modules/*
node_modules/*
test.js

View File

@@ -1,6 +1,6 @@
# Steam Community for Node.js
This lightweight module provides an easy interface to login to the Steam Community website. You can also login to the Steam Community website via [node-steam](https://github.com/seishun/node-steam)'s `webLogOn` method, but this module may be useful if you don't want to run an entire Steam instance.
This lightweight 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 but doesn't support CAPTCHAs, so make sure you don't provide Steam with an incorrect password.
@@ -10,55 +10,6 @@ Install it from npm:
$ npm install steamcommunity
# Usage
# Documentation
First, instantiate the `SteamCommunity` object:
```js
var SteamCommunity = require('steamcommunity');
var community = new SteamCommunity("username", "password");
```
Then, simply call the `login` method:
```js
community.login(function(err, sessionID, cookies, steamguard) {
// Do something with the sessionID and cookies.
// The steamguard parameter is only meaningful if you've entered a Steam Guard auth code, as shown below.
});
```
# Steam Guard
In order to authenticate with a Steam Guard authorization, you need to provide your 64-bit Steam ID and machineAuth value to the constructor:
```js
var SteamCommunity = require('steamcommunity');
var community = new SteamCommunity("username", "password", "steamid64", "machineAuth");
```
If you don't have a prior authorization, you can get one by logging in as normal (without the steamID and machineAuth parameters). The callback to the `login` method will get `SteamGuard` as `err`. This means that an email has been sent to the email address tied to your account. Once you get the code, just call `login` again with the code as the first parameter:
```js
community.login('ABCDE', function(err, sessionID, cookies, steamguard) {
// steamguard is now an object with two properties: steamID and machineAuth. You'll want to save these and provide them to subsequent constructors.
// If you call login again on this instance of SteamCommunity, the Steam Guard machineAuth will be sent automatically so you don't need to reconstruct a new instance.
});
```
# Methods
## Constructor: SteamCommunity(username, password[, steamID, machineAuth])
Instantiate a new instance of `SteamCommunity`. `steamID` and `machineAuth` are optional, but if you have them and your account is protectd by Steam Guard, you should provide them. Otherwise, you'll get a `SteamGuard` error when you try to login.
## login([code, ]callback)
Attempts to login to Steam Community using the credentials supplied in the constructor. If you have previously received a `SteamGuard` error and you have an email auth code, supply it here as the first parameter.
The `callback` has 4 parameters:
- `err` - An error that occurred, or `null` on success. The value will be `SteamGuard` if you need to supply an email auth code.
- `sessionID` - This session's sessionID. Whatever module you're using with this will know what to do with it.
- `cookies` - An array of session cookies. The format is the same as that returned by [node-steam](https://github.com/seishun/node-steam)'s `webLogOn` method, so anything designed to work with node-steam will also work with this.
- `steamguard` - If you supplied an email auth code, this will contain your `steamID` and `machineAuth` code, which you should save and provide for subsequent logins.
As of version 1.0.0, documentation is on the [GitHub wiki](https://github.com/DoctorMcKay/node-steamcommunity/wiki).

126
classes/CMarketItem.js Normal file
View File

@@ -0,0 +1,126 @@
var SteamCommunity = require('../index.js');
var Cheerio = require('cheerio');
SteamCommunity.prototype.getMarketItem = function(appid, hashName, callback) {
var self = this;
this.request("https://steamcommunity.com/market/listings/" + appid + "/" + encodeURIComponent(hashName), function(err, response, body) {
if(self._checkHttpError(err, response, callback)) {
return;
}
var $ = Cheerio.load(body);
if($('.market_listing_table_message') && $('.market_listing_table_message').text().trim() == 'There are no listings for this item.') {
callback(new Error("There are no listings for this item."));
return;
}
var item = new CMarketItem(self, body, $);
if(item.commodity) {
item.updatePrice(function(err) {
if(err) {
callback(err);
} else {
callback(null, item);
}
});
} else {
callback(null, item);
}
});
};
function CMarketItem(community, body, $) {
this._community = community;
this._$ = $;
this._country = "US";
var match = body.match(/var g_strCountryCode = "([^"]+)";/);
if(match) {
this._country = match[1];
}
this.commodity = false;
var match = body.match(/Market_LoadOrderSpread\(\s*(\d+)\s*\);/);
if(match) {
this.commodity = true;
this.commodityID = parseInt(match[1], 10);
}
this.medianSalePrices = null;
match = body.match(/var line1=([^;]+);/);
if(match) {
try {
this.medianSalePrices = JSON.parse(match[1]);
this.medianSalePrices = this.medianSalePrices.map(function(item) {
return {
"hour": new Date(item[0]),
"price": item[1],
"quantity": parseInt(item[2], 10)
};
});
} catch(e) {
// ignore
}
}
this.quantity = 0;
this.lowestPrice = 0;
if(!this.commodity) {
var total = $('#searchResults_total');
if(total) {
this.quantity = parseInt(total.text().replace(/[^\d]/g, '').trim(), 10);
}
var lowest = $('.market_listing_price.market_listing_price_with_fee');
if(lowest[0]) {
this.lowestPrice = parseInt($(lowest[0]).text().replace(/[^\d]/g, '').trim(), 10);
}
}
// TODO: Buying listings and placing buy orders
}
CMarketItem.prototype.updatePrice = function(callback) {
if(!this.commodity) {
throw new Error("Cannot update price for non-commodity item");
}
// TODO: Currency option maybe?
var self = this;
this._community.request({
"uri": "https://steamcommunity.com/market/itemordershistogram?country=US&language=english&currency=1&item_nameid=" + this.commodityID,
"json": true,
}, function(err, response, body) {
if(self._community._checkHttpError(err, response, callback)) {
return;
}
if(body.success != 1) {
if(callback) {
callback(new Error("Error " + body.success));
}
return;
}
var match = (body.sell_order_summary || '').match(/<span class="market_commodity_orders_header_promote">(\d+)<\/span>/);
if(match) {
self.quantity = parseInt(match[1], 10);
}
self.buyQuantity = 0;
match = (body.buy_order_summary || '').match(/<span class="market_commodity_orders_header_promote">(\d+)<\/span>/);
if(match) {
self.buyQuantity = parseInt(match[1], 10);
}
self.lowestPrice = parseInt(body.lowest_sell_order, 10);
self.highestBuyOrder = parseInt(body.highest_buy_order, 10);
// TODO: The tables?
if(callback) {
callback(null);
}
});
};

View File

@@ -0,0 +1,85 @@
var SteamCommunity = require('../index.js');
var Cheerio = require('cheerio');
SteamCommunity.prototype.marketSearch = function(options, callback) {
var qs = {};
if(typeof options === 'string') {
qs.query = options;
} else {
qs.query = options.query || '';
qs.appid = options.appid;
qs.search_descriptions = options.searchDescriptions ? 1 : 0;
if(qs.appid) {
for(var i in options) {
if(['query', 'appid', 'searchDescriptions'].indexOf(i) != -1) {
continue;
}
// This is a tag
qs['category_' + qs.appid + '_' + i + '[]'] = 'tag_' + options[i];
}
}
}
qs.start = 0;
qs.count = 100;
qs.sort_column = 'price';
qs.sort_dir = 'asc';
performSearch.call(this, this.request, qs, [], callback);
};
function performSearch(request, qs, results, callback) {
var self = this;
request({
"uri": "https://steamcommunity.com/market/search/render/",
"qs": qs,
"headers": {
"referer": "https://steamcommunity.com/market/search"
},
"json": true
}, function(err, response, body) {
if(self._checkHttpError(err, response, callback)) {
return;
}
if(!body.success) {
callback(new Error("Success is not true"));
return;
}
if(!body.results_html) {
callback(new Error("No results_html in response"));
return;
}
var $ = Cheerio.load(body.results_html);
if($('.market_listing_table_message').length > 0) {
callback(new Error($('.market_listing_table_message').text()));
return;
}
var rows = $('.market_listing_row_link');
for(var i = 0; i < rows.length; i++) {
results.push(new CMarketSearchResult($(rows[i])));
}
if(body.start + body.pagesize >= body.total_count) {
callback(null, results);
} else {
qs.start += body.pagesize;
performSearch(request, qs, results, callback);
}
});
}
function CMarketSearchResult(row) {
var match = row.attr('href').match(/\/market\/listings\/(\d+)\/(.+)/);
this.appid = parseInt(match[1], 10);
this.market_hash_name = decodeURIComponent(match[2]);
this.image = row.find('.market_listing_item_img').attr('src').match(/^https?:\/\/[^\/]+\/economy\/image\/[^\/]+\//)[0];
this.price = parseInt(row.find('.market_listing_their_price .market_table_value span').text().replace(/[^\d]+/g, ''), 10);
this.quantity = parseInt(row.find('.market_listing_num_listings_qty').text().replace(/[^\d]+/g, ''), 10);
}

286
classes/CSteamGroup.js Normal file
View File

@@ -0,0 +1,286 @@
var SteamCommunity = require('../index.js');
var SteamID = require('steamid');
var xml2js = require('xml2js');
SteamCommunity.prototype.getSteamGroup = function(id, callback) {
if(typeof id !== 'string' && !(typeof id === 'object' && id.__proto__ === SteamID.prototype)) {
throw new Error("id parameter should be a group URL string or a SteamID object");
}
if(typeof id === 'object' && (id.universe != SteamID.Universe.PUBLIC || id.type != SteamID.Type.CLAN)) {
throw new Error("SteamID must stand for a clan account in the public universe");
}
var self = this;
this.request("https://steamcommunity.com/" + (typeof id === 'string' ? "groups/" + id : "gid/" + id.toString()) + "/memberslistxml/?xml=1", function(err, response, body) {
if(self._checkHttpError(err, response, callback)) {
return;
}
if(self._checkCommunityError(body, callback)) {
return;
}
xml2js.parseString(body, function(err, result) {
if(err) {
callback(err);
return;
}
callback(null, new CSteamGroup(self, result.memberList));
});
});
};
function CSteamGroup(community, groupData) {
this._community = community;
this.steamID = new SteamID(groupData.groupID64[0]);
this.name = groupData.groupDetails[0].groupName[0];
this.url = groupData.groupDetails[0].groupURL[0];
this.headline = groupData.groupDetails[0].headline[0];
this.summary = groupData.groupDetails[0].summary[0];
this.avatarHash = groupData.groupDetails[0].avatarIcon[0].match(/([0-9a-f]+)\.jpg$/)[1];
this.members = parseInt(groupData.groupDetails[0].memberCount[0], 10);
this.membersInChat = parseInt(groupData.groupDetails[0].membersInChat[0], 10);
this.membersInGame = parseInt(groupData.groupDetails[0].membersInGame[0], 10);
this.membersOnline = parseInt(groupData.groupDetails[0].membersOnline[0], 10);
}
CSteamGroup.prototype.getAvatarURL = function(size, protocol) {
size = size || '';
protocol = protocol || 'http://';
var url = protocol + "steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/" + this.avatarHash.substring(0, 2) + "/" + this.avatarHash;
if(size == 'full' || size == 'medium') {
return url + "_" + size + ".jpg";
} else {
return url + ".jpg";
}
};
CSteamGroup.prototype.getMembers = function(callback, members, link) {
members = members || [];
link = link || "http://steamcommunity.com/gid/" + this.steamID.toString() + "/memberslistxml/?xml=1";
var self = this;
this._community.request(link, function(err, response, body) {
if(self._community._checkHttpError(err, response, callback)) {
return;
}
xml2js.parseString(body, function(err, result) {
if(err) {
callback(err);
return;
}
members = members.concat(result.memberList.members[0].steamID64.map(function(steamID) {
return new SteamID(steamID);
}));
if(result.memberList.nextPageLink) {
self.getMembers(callback, members, result.memberList.nextPageLink[0]);
} else {
callback(null, members);
}
});
});
};
CSteamGroup.prototype.join = function(callback) {
var form = {
"action": "join",
"sessionID": this._community.getSessionID()
};
var self = this;
this._community.request.post("https://steamcommunity.com/gid/" + this.steamID.toString(), {"form": form}, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode >= 400) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
if(self._community._checkCommunityError(body, callback)) {
return;
}
callback(null);
});
};
CSteamGroup.prototype.leave = function(callback) {
var form = {
"sessionID": this._community.getSessionID(),
"action": "leaveGroup",
"groupId": this.steamID.toString()
};
var self = this;
this._community._myProfile("home_process", form, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode >= 400) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
if(self._community._checkCommunityError(body, callback)) {
return;
}
callback(null);
});
};
CSteamGroup.prototype.postAnnouncement = function(headline, content, callback) {
var form = {
"sessionID": this._community.getSessionID(),
"action": "post",
"headline": headline,
"body": content
};
this._community.request.post("https://steamcommunity.com/gid/" + this.steamID.toString() + "/announcements", {"form": form}, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode >= 400) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
if(self._community._checkCommunityError(body, callback)) {
return;
}
callback(null);
});
};
CSteamGroup.prototype.scheduleEvent = function(name, type, description, time, server, callback) {
// Event types: ChatEvent - Chat, OtherEvent - A lil somethin somethin, PartyEvent - Party!, MeetingEvent - Important meeting, SpecialCauseEvent - Special cause (charity ball?), MusicAndArtsEvent - Music or Art type thing, SportsEvent - Sporting endeavor, TripEvent - Out of town excursion
// Passing a number for type will make it a game event for that appid
if(typeof server === 'function') {
callback = server;
server = {"ip": "", "password": ""};
} else if(typeof server === 'string') {
server = {"ip": server, "password": ""};
} else {
server = {"ip": "", "password": ""};
}
var form = {
"sessionid": this._community.getSessionID(),
"action": "newEvent",
"tzOffset": new Date().getTimezoneOffset() * -60,
"name": name,
"type": (typeof type === 'number' || !isNaN(parseInt(type, 10)) ? "GameEvent" : type),
"appID": (typeof type === 'number' || !isNaN(parseInt(type, 10)) ? type : ''),
"serverIP": server.ip,
"serverPassword": server.password,
"notes": description,
"eventQuickTime": "now"
};
if(time === null) {
form.startDate = 'MM/DD/YY';
form.startHour = '12';
form.startMinute = '00';
form.startAMPM = 'PM';
form.timeChoice = 'quick';
} else {
form.startDate = (time.getMonth() + 1 < 10 ? '0' : '') + (time.getMonth() + 1) + '/' + (time.getDate() < 10 ? '0' : '') + time.getDate() + '/' + time.getFullYear().toString().substring(2);
form.startHour = (time.getHours() === 0 ? '12' : (time.getHours() > 12 ? time.getHours() - 12 : time.getHours()));
form.startMinute = (time.getMinutes() < 10 ? '0' : '') + time.getMinutes();
form.startAMPM = (time.getHours() <= 12 ? 'AM' : 'PM');
form.timeChoice = 'specific';
}
var self = this;
this._community.request.post("https://steamcommunity.com/gid/" + this.steamID.toString() + "/eventEdit", {"form": form}, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode >= 400) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
if(self._community._checkCommunityError(body, callback)) {
return;
}
callback(null);
});
};
CSteamGroup.prototype.setPlayerOfTheWeek = function(steamID, callback) {
var form = {
"xml": 1,
"action": "potw",
"memberId": steamID.getSteam3RenderedID(),
"sessionid": this._community.getSessionID()
};
var self = this;
this._community.request.post("https://steamcommunity.com/gid/" + this.steamID.toString() + "/potwEdit", {"form": form}, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode != 200) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
xml2js.parseString(body, function(err, results) {
if(err) {
callback(err);
return;
}
if(results.response.results[0] == 'OK') {
callback(null, new SteamID(results.response.oldPOTW[0]), new SteamID(results.response.newPOTW[0]));
} else {
callback(new Error(results.response.results[0]));
}
});
});
};
CSteamGroup.prototype.kick = function(steamID, callback) {
var form = {
"sessionID": this._community.getSessionID(),
"action": "kick",
"memberId": steamID.toString(),
"queryString": ""
};
var self = this;
this._community.request.post("https://steamcommunity.com/gid/" + this.steamID.toString() + "/membersManage", {"form": form}, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode >= 400) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
if(self._community._checkCommunityError(body, callback)) {
return;
}
callback(null);
});
};

230
classes/CSteamUser.js Normal file
View File

@@ -0,0 +1,230 @@
var SteamCommunity = require('../index.js');
var SteamID = require('steamid');
var xml2js = require('xml2js');
SteamCommunity.prototype.getSteamUser = function(id, callback) {
if(typeof id !== 'string' && !(typeof id === 'object' && id.__proto__ === SteamID.prototype)) {
throw new Error("id parameter should be a user URL string or a SteamID object");
}
if(typeof id === 'object' && (id.universe != SteamID.Universe.PUBLIC || id.type != SteamID.Type.INDIVIDUAL)) {
throw new Error("SteamID must stand for an individual account in the public universe");
}
var self = this;
this.request("http://steamcommunity.com/" + (typeof id === 'string' ? "id/" + id : "profiles/" + id.toString()) + "/?xml=1", function(err, response, body) {
if(self._checkHttpError(err, response, callback)) {
return;
}
if(self._checkCommunityError(body, callback)) {
return;
}
xml2js.parseString(body, function(err, result) {
if(err || (!result.response && !result.profile)) {
callback(err || new Error("No valid response"));
return;
}
if(result.response && result.response.error && result.response.error.length) {
callback(new Error(result.response.error[0]));
return;
}
// Try and find custom URL from redirect
var customurl = null;
if(response.request.redirects && response.request.redirects.length) {
var match = response.request.redirects[0].redirectUri.match(/https?:\/\/steamcommunity\.com\/id\/([^/])+\/\?xml=1/);
if(match) {
customurl = match[1];
}
}
callback(null, new CSteamUser(self, result.profile, customurl));
});
});
};
function CSteamUser(community, userData, customurl) {
this._community = community;
this.steamID = new SteamID(userData.steamID64[0]);
this.name = userData.steamID[0];
this.onlineState = userData.onlineState[0];
this.stateMessage = userData.stateMessage[0];
this.privacyState = userData.privacyState[0];
this.visibilityState = userData.visibilityState[0];
this.avatarHash = userData.avatarIcon[0].match(/([0-9a-f]+)\.[a-z]+$/)[1];
this.vacBanned = !!userData.vacBanned[0];
this.tradeBanState = userData.tradeBanState[0];
this.isLimitedAccount = !!userData.isLimitedAccount[0];
this.customURL = userData.customURL ? userData.customURL[0] : customurl;
if(this.visibilityState == 3) {
this.memberSince = new Date(userData.memberSince[0].replace(/(\d{1,2})(st|nd|th)/, "$1"));
this.location = userData.location[0] || null;
this.realName = userData.realname[0] || null;
this.summary = userData.summary[0] || null;
} else {
this.memberSince = null;
this.location = null;
this.realName = null;
this.summary = null;
}
// Maybe handle mostPlayedGames?
this.groups = null;
this.primaryGroup = null;
var self = this;
if(userData.groups && userData.groups[0] && userData.groups[0].group) {
this.groups = userData.groups[0].group.map(function(group) {
if(group['$'] && group['$'].isPrimary) {
self.primaryGroup = new SteamID(group.groupID64[0]);
}
return new SteamID(group.groupID64[0]);
});
}
}
CSteamUser.getAvatarURL = function(hash, size, protocol) {
size = size || '';
protocol = protocol || 'http://';
var url = protocol + "steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/" + hash.substring(0, 2) + "/" + hash;
if(size == 'full' || size == 'medium') {
return url + "_" + size + ".jpg";
} else {
return url + ".jpg";
}
};
CSteamUser.prototype.getAvatarURL = function(size, protocol) {
return CSteamUser.getAvatarURL(this.avatarHash, size, protocol);
};
CSteamUser.prototype.addFriend = function(callback) {
var self = this;
this._community.request.post('https://steamcommunity.com/actions/AddFriendAjax', {"form": {"accept_invite": 0, "sessionID": this._community.getSessionID(), "steamid": this.steamID.toString()}}, function(err, response, body) {
if(!callback) {
return;
}
if(self._community._checkHttpError(err, response, callback)) {
return;
}
var json;
try {
json = JSON.parse(body);
} catch(e) {
callback(e);
return;
}
if(json.success) {
callback(null);
} else {
callback(new Error("Unknown error"));
}
});
};
CSteamUser.prototype.acceptFriendRequest = function(callback) {
var self = this;
this._community.request.post('https://steamcommunity.com/actions/AddFriendAjax', {"form": {"accept_invite": 1, "sessionID": this._community.getSessionID(), "steamid": this.steamID.toString()}}, function(err, response, body) {
if(!callback) {
return;
}
if(self._community._checkHttpError(err, response, callback)) {
return;
}
callback(null);
});
};
CSteamUser.prototype.removeFriend = function(callback) {
var self = this;
this._community.request.post('https://steamcommunity.com/actions/RemoveFriendAjax', {"form": {"sessionID": this._community.getSessionID(), "steamid": this.steamID.toString()}}, function(err, response, body) {
if(!callback) {
return;
}
if(self._community._checkHttpError(err, response, callback)) {
return;
}
callback(null);
});
};
CSteamUser.prototype.blockCommunication = function(callback) {
var self = this;
this._community.request.post('https://steamcommunity.com/actions/BlockUserAjax', {"form": {"sessionID": this._community.getSessionID(), "steamid": this.steamID.toString()}}, function(err, response, body) {
if(!callback) {
return;
}
if(self._community._checkHttpError(err, response, callback)) {
return;
}
callback(null);
});
};
CSteamUser.prototype.unblockCommunication = function(callback) {
var form = {"action": "unignore"};
form['friends[' + this.steamID.toString() + ']'] = 1;
this._community._myProfile('friends/blocked/', form, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode >= 400) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
callback(null);
});
};
CSteamUser.prototype.comment = function(message, callback) {
this._community.request.post('https://steamcommunity.com/comment/Profile/post/' + this.steamID.toString() + '/-1/', {"form": {
"comment": message,
"count": 6,
"sessionid": this._community.getSessionID()
}}, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode != 200) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
var json;
try {
json = JSON.parse(body);
} catch(e) {
callback(e);
return;
}
if(json.success) {
callback(null);
} else if(json.error) {
callback(new Error(json.error));
} else {
callback(new Error("Unknown error"));
}
});
};

253
components/chat.js Normal file
View File

@@ -0,0 +1,253 @@
var SteamCommunity = require('../index.js');
var SteamID = require('steamid');
SteamCommunity.ChatState = {
"Offline": 0,
"LoggingOn": 1,
"LogOnFailed": 2,
"LoggedOn": 3
};
SteamCommunity.PersonaState = {
"Offline": 0,
"Online": 1,
"Busy": 2,
"Away": 3,
"Snooze": 4,
"LookingToTrade": 5,
"LookingToPlay": 6,
"Max": 7
};
SteamCommunity.PersonaStateFlag = {
"HasRichPresence": 1,
"InJoinableGame": 2,
"OnlineUsingWeb": 256,
"OnlineUsingMobile": 512,
"OnlineUsingBigPicture": 1024
};
SteamCommunity.prototype.chatLogon = function(interval, uiMode) {
if(this.chatState == SteamCommunity.ChatState.LoggingOn || this.chatState == SteamCommunity.ChatState.LoggedOn) {
return;
}
interval = interval || 500;
uiMode = uiMode || "web";
this.emit('debug', 'Requesting chat WebAPI token');
this.chatState = SteamCommunity.ChatState.LoggingOn;
var self = this;
this.request("https://steamcommunity.com/chat", function(err, response, body) {
if(err || response.statusCode != 200) {
self.emit('debug', 'Error requesting chat WebAPI token: ' + (err ? err.message : "HTTP error " + response.statusCode));
self.chatState = SteamCommunity.ChatState.LogOnFailed;
setTimeout(self.chatLogon.bind(self), 5000);
return;
}
var match = body.match(/[0-9a-f]{32}/);
if(!match) {
self.emit('debug', 'Couldn\'t find a WebAPI chat token in the response.');
self.chatState = SteamCommunity.ChatState.LogOnFailed;
setTimeout(self.chatLogon.bind(self), 5000);
return;
}
self.request.post({
"uri": "https://api.steampowered.com/ISteamWebUserPresenceOAuth/Logon/v1",
"form": {
"ui_mode": uiMode,
"access_token": match[0]
},
"json": true
}, function(err, response, body) {
if(err || response.statusCode != 200) {
self.emit('debug', 'Error logging into webchat: ' + (err ? err.message : "HTTP error " + response.statusCode));
self.chatState = SteamCommunity.ChatState.LogOnFailed;
setTimeout(self.chatLogon.bind(self), 5000);
return;
}
if(body.error != 'OK') {
self.emit('debug', 'Error logging into webchat: ' + body.error);
self.chatState = SteamCommunity.ChatState.LogOnFailed;
setTimeout(self.chatLogon.bind(self), 5000);
return;
}
self._chat = {
"umqid": body.umqid,
"message": body.message,
"accessToken": match[0],
"interval": interval
};
self.chatFriends = {};
self.chatState = SteamCommunity.ChatState.LoggedOn;
self.emit('chatLoggedOn');
self._chatPoll();
});
});
};
SteamCommunity.prototype.chatMessage = function(recipient, text, type, callback) {
if(this.chatState != SteamCommunity.ChatState.LoggedOn) {
throw new Error("Chat must be logged on before messages can be sent");
}
if(typeof recipient === 'string') {
recipient = new SteamID(recipient);
}
if(typeof type === 'function') {
callback = type;
type = 'saytext';
}
type = type || 'saytext';
this.request.post({
"uri": "https://api.steampowered.com/ISteamWebUserPresenceOAuth/Message/v1",
"form": {
"access_token": this._chat.accessToken,
"steamid_dst": recipient.toString(),
"text": text,
"type": type,
"umqid": this._chat.umqid
},
"json": true
}, function(err, response, body) {
if(!callback) {
return;
}
if(self._checkHttpError(err, response, callback)) {
return;
}
if(body.error != 'OK') {
callback(new Error(body.error));
} else {
callback(null);
}
});
};
SteamCommunity.prototype.chatLogoff = function() {
var self = this;
this.request.post({
"uri": "https://api.steampowered.com/ISteamWebUserPresenceOAuth/Logoff/v1",
"form": {
"access_token": this._chat.accessToken,
"umqid": this._chat.umqid
}
}, function(err, response, body) {
if(err || response.statusCode != 200) {
self.emit('debug', 'Error logging off of chat: ' + (err ? err.message : "HTTP error " + response.statusCode));
setTimeout(self.chatLogoff.bind(self), 1000);
} else {
self.emit('chatLoggedOff');
clearTimeout(self._chat.timer);
delete self._chat;
delete self.chatFriends;
self.chatState = SteamCommunity.ChatState.Offline;
}
});
};
SteamCommunity.prototype._chatPoll = function() {
this.emit('debug', 'Doing chat poll');
var self = this;
this.request.post({
"uri": "https://api.steampowered.com/ISteamWebUserPresenceOAuth/Poll/v1",
"form": {
"umqid": self._chat.umqid,
"message": self._chat.message,
"pollid": 1,
"sectimeout": 20,
"secidletime": 0,
"use_accountids": 1,
"access_token": self._chat.accessToken
},
"json": true
}, function(err, response, body) {
if(self.chatState == SteamCommunity.ChatState.Offline) {
return;
}
self._chat.timer = setTimeout(self._chatPoll.bind(self), self._chat.interval);
if(err || response.statusCode != 200) {
self.emit('debug', 'Error in chat poll: ' + (err ? err.message : "HTTP error " + response.statusCode));
return;
}
if(body.error != 'OK') {
self.emit('debug', 'Error in chat poll: ' + body.error);
return;
}
self._chat.message = body.messagelast;
(body.messages || []).forEach(function(message) {
var sender = new SteamID();
sender.universe = SteamID.Universe.PUBLIC;
sender.type = SteamID.Type.INDIVIDUAL;
sender.instance = SteamID.Instance.DESKTOP;
sender.accountid = message.accountid_from;
switch(message.type) {
case 'personastate':
self._chatUpdatePersona(sender);
break;
case 'saytext':
self.emit('chatMessage', sender, message.text);
break;
case 'typing':
self.emit('chatTyping', sender);
break;
default:
self.emit('debug', 'Unhandled chat message type: ' + message.type);
}
});
});
};
SteamCommunity.prototype._chatUpdatePersona = function(steamID) {
this.emit('debug', 'Updating persona data for ' + steamID);
var self = this;
this.request({
"uri": "https://steamcommunity.com/chat/friendstate/" + steamID.accountid,
"json": true
}, function(err, response, body) {
if(err || response.statusCode != 200) {
self.emit('debug', 'Chat update persona error: ' + (err ? err.message : "HTTP error " + response.statusCode));
setTimeout(function() {
self._chatUpdatePersona(steamID);
}, 2000);
return;
}
var persona = {
"steamID": steamID,
"personaName": body.m_strName,
"personaState": body.m_ePersonaState,
"personaStateFlags": body.m_nPersonaStateFlags || 0,
"avatarHash": body.m_strAvatarHash,
"inGame": !!body.m_bInGame,
"inGameAppID": body.m_nInGameAppID ? parseInt(body.m_nInGameAppID, 10) : null,
"inGameName": body.m_strInGameName || null
};
self.emit('chatPersonaState', steamID, persona);
self.chatFriends[steamID.getSteamID64()] = persona;
});
};

213
components/profile.js Normal file
View File

@@ -0,0 +1,213 @@
var SteamCommunity = require('../index.js');
var SteamID = require('steamid');
var Cheerio = require('cheerio');
SteamCommunity.PrivacyState = {
"Private": 1,
"FriendsOnly": 2,
"Public": 3
};
var CommentPrivacyState = {
"1": "commentselfonly",
"2": "commentfriendsonly",
"3": "commentanyone"
};
SteamCommunity.prototype.setupProfile = function(callback) {
var self = this;
this._myProfile("edit?welcomed=1", null, function(err, response, body) {
if(!callback) {
return;
}
if(err || response.statusCode != 200) {
callback(err || new Error("HTTP error " + response.statusCode));
} else {
callback(null);
}
});
};
SteamCommunity.prototype.editProfile = function(settings, callback) {
var self = this;
this._myProfile("edit", null, function(err, response, body) {
if(err || response.statusCode != 200) {
if(callback) {
callback(err || new Error("HTTP error " + response.statusCode));
}
return;
}
var $ = Cheerio.load(body);
var form = $('#editForm');
if(!form) {
if(callback) {
callback(new Error("Malformed response"));
}
return;
}
var values = {};
form.serializeArray().forEach(function(item) {
values[item.name] = item.value;
});
for(var i in settings) {
if(!settings.hasOwnProperty(i)) {
continue;
}
switch(i) {
case 'name':
values.personaName = settings[i];
break;
case 'realName':
values.real_name = settings[i];
break;
case 'summary':
values.summary = settings[i];
break;
case 'country':
values.country = settings[i];
break;
case 'state':
values.state = settings[i];
break;
case 'city':
values.city = settings[i];
break;
case 'customURL':
values.customURL = settings[i];
break;
case 'background':
// The assetid of our desired profile background
values.profile_background = settings[i];
break;
case 'featuredBadge':
// Currently, game badges aren't supported
values.favorite_badge_badgeid = settings[i];
break;
case 'primaryGroup':
if(typeof settings[i] === 'object' && settings[i].accountid) {
values.primary_group_steamid = settings[i].accountid;
} else {
values.primary_group_steamid = new SteamID(settings[i]).accountid;
}
break;
// TODO: profile showcases
}
}
self._myProfile("edit", values, function(err, response, body) {
if(err || response.statusCode != 200) {
if(callback) {
callback(err || new Error("HTTP error " + response.statusCode));
}
return;
}
// Check for an error
var $ = Cheerio.load(body);
var error = $('#errorText .formRowFields');
if(error) {
error = error.text().trim();
if(error) {
if(callback) {
callback(new Error(error));
}
return;
}
}
if(callback) {
callback(null);
}
});
});
};
SteamCommunity.prototype.profileSettings = function(settings, callback) {
var self = this;
this._myProfile("edit/settings", null, function(err, response, body) {
if(err || response.statusCode != 200) {
if(callback) {
callback(err || new Error("HTTP error " + response.statusCode));
}
return;
}
var $ = Cheerio.load(body);
var form = $('#editForm');
if(!form) {
if(callback) {
callback(new Error("Malformed response"));
}
return;
}
var values = {};
form.serializeArray().forEach(function(item) {
values[item.name] = item.value;
});
for(var i in settings) {
if(!settings.hasOwnProperty(i)) {
continue;
}
switch(i) {
case 'profile':
values.privacySetting = settings[i];
break;
case 'comments':
values.commentSetting = CommentPrivacyState[settings[i]];
break;
case 'inventory':
values.inventoryPrivacySetting = settings[i];
break;
case 'inventoryGifts':
values.inventoryGiftPrivacy = settings[i] ? 1 : 0;
break;
case 'emailConfirmation':
values.tradeConfirmationSetting = settings[i] ? 1 : 0;
break;
}
}
self._myProfile("edit/settings", values, function(err, response, body) {
if(err || response.statusCode != 200) {
if(callback) {
callback(err || new Error("HTTP error " + response.statusCode));
}
return;
}
if(callback) {
callback(null);
}
});
});
};

337
index.js
View File

@@ -1,33 +1,32 @@
var Request = require('request');
var RSA = require('node-bignumber').Key;
var hex2b64 = require('node-bignumber').hex2b64;
var SteamID = require('steamid');
require('util').inherits(SteamCommunity, require('events').EventEmitter);
module.exports = SteamCommunity;
function SteamCommunity(username, password, steamID, machineAuth) {
this._username = username;
this._password = password;
this._steamID = steamID;
this._sentry = machineAuth;
SteamCommunity.SteamID = SteamID;
function SteamCommunity() {
this._jar = Request.jar();
this._captchaGid = -1;
this.request = Request.defaults({"jar": this._jar, "timeout": 50000});
this.chatState = SteamCommunity.ChatState.Offline;
// English
this._jar.setCookie(Request.cookie('Steam_Language=english'), 'https://steamcommunity.com');
}
SteamCommunity.prototype.login = function(authCode, callback) {
if(typeof authCode === 'function') {
callback = authCode;
authCode = "";
}
var request;
if(this._steamID && this._sentry) {
var jar = Request.jar();
request = Request.defaults({"jar": jar});
jar.setCookieSync(Request.cookie('steamMachineAuth' + this._steamID + '=' + this._sentry), 'https://steamcommunity.com');
} else {
request = Request;
SteamCommunity.prototype.login = function(details, callback) {
if(details.steamguard) {
var parts = details.steamguard.split('||');
this._jar.setCookie(Request.cookie('steamMachineAuth' + parts[0] + '=' + encodeURIComponent(parts[1])), 'https://steamcommunity.com');
}
var self = this;
request.post("https://steamcommunity.com/login/getrsakey/", {"form": {"username": this._username}}, function(err, response, body) {
this.request.post("https://steamcommunity.com/login/getrsakey/", {"form": {"username": details.accountName}}, function(err, response, body) {
if(err) {
callback(err);
return;
@@ -45,64 +44,274 @@ SteamCommunity.prototype.login = function(authCode, callback) {
key.setPublic(json.publickey_mod, json.publickey_exp);
var form = {
"captcha_text": "",
"captchagid": -1,
"emailauth": authCode || "",
"captcha_text": details.captcha || "",
"captchagid": self._captchaGid,
"emailauth": details.authCode || "",
"emailsteamid": "",
"loginfriendlyname": "",
"password": hex2b64(key.encrypt(self._password)),
"remember_login": false,
"password": hex2b64(key.encrypt(details.password)),
"remember_login": "true",
"rsatimestamp": json.timestamp,
"twofactorcode": "",
"username": self._username
"twofactorcode": details.twoFactorCode || "",
"username": details.accountName
};
request.post("https://steamcommunity.com/login/dologin/", {"form": form}, function(err, response, body) {
if(err) {
callback(err);
self.request.post({
"uri": "https://steamcommunity.com/login/dologin/",
"json": true,
"form": form
}, function(err, response, body) {
if(self._checkHttpError(err, response, callback)) {
return;
}
var json;
try {
json = JSON.parse(body);
} catch(e) {
callback(e);
return;
}
if(!json.success) {
callback(json.message);
if(!body.success && body.emailauth_needed) {
// Steam Guard (email)
var 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) {
var error = new Error("CAPTCHA");
error.captchaurl = "https://steamcommunity.com/public/captcha.php?gid=" + body.captcha_gid;
self._captchaGid = body.captcha_gid;
callback(error);
} else if(!body.success) {
callback(new Error(body.message || "Unknown error"));
} else {
var cookies = [];
for(var i = 0; i < response.headers['set-cookie'].length; i++) {
var header = response.headers['set-cookie'][i];
var pos = header.indexOf(';');
if(pos != -1) {
header = header.substring(0, pos);
var sessionID = generateSessionID();
self._jar.setCookie(Request.cookie('sessionid=' + sessionID), 'http://steamcommunity.com');
self.steamID = new SteamID(body.transfer_parameters.steamid);
var cookies = self._jar.getCookieString("https://steamcommunity.com").split(';').map(function(cookie) {
return cookie.trim();
});
// 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;
}
cookies.push(header);
}
var sessionID = Math.floor(Math.random() * 1000000000);
cookies.push('sessionid=' + sessionID);
if(self._steamID && self._sentry) {
cookies.push('steamMachineAuth' + self._steamID + '=' + self._sentry);
}
var steamguard = {};
if(json.transfer_parameters.steamid && json.transfer_parameters.webcookie) {
steamguard.steamID = json.transfer_parameters.steamid;
steamguard.machineAuth = json.transfer_parameters.webcookie;
self._steamID = steamguard.steamID;
self._sentry = steamguard.machineAuth;
}
callback(null, sessionID, cookies, steamguard);
}
});
});
};
};
SteamCommunity.prototype.setCookies = function(cookies) {
var self = this;
cookies.forEach(function(cookie) {
var cookieName = cookie.match(/(.+)=/)[1];
if(cookieName == 'steamLogin') {
self.steamID = new SteamID(cookie.match(/=(\d+)/)[1]);
}
self._jar.setCookie(Request.cookie(cookie), (cookieName.match(/^steamMachineAuth/) || cookieName.match(/Secure$/) ? "https://" : "http://") + "steamcommunity.com");
});
};
SteamCommunity.prototype.getSessionID = function() {
var cookies = this._jar.getCookieString("http://steamcommunity.com").split(';');
for(var i = 0; i < cookies.length; i++) {
var match = cookies[i].trim().match(/([^=]+)=(.+)/);
if(match[1] == 'sessionid') {
return decodeURIComponent(match[2]);
}
}
var sessionID = generateSessionID();
this._jar.setCookie(Request.cookie('sessionid=' + sessionID), "http://steamcommunity.com");
return sessionID;
};
function generateSessionID() {
return Math.floor(Math.random() * 1000000000);
};
SteamCommunity.prototype.getWebApiKey = function(domain, callback) {
var self = this;
this.request("https://steamcommunity.com/dev/apikey", function(err, response, body) {
if(self._checkHttpError(err, response, callback)) {
return;
}
if(body.match(/<h2>Access Denied<\/h2>/)) {
return callback("Access Denied");
}
var 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.request.post('https://steamcommunity.com/dev/registerkey', {
"form": {
"domain": domain,
"agreeToTerms": "agreed",
"sessionid": self.getSessionID(),
"Submit": "Register"
}
}, function(err, response, body) {
if(err || response.statusCode >= 400) {
return callback(err.message || "HTTP error " + response.statusCode);
}
self.getWebApiKey(domain, callback);
});
}
});
};
SteamCommunity.prototype.parentalUnlock = function(pin, callback) {
this.request.post("https://steamcommunity.com/parental/ajaxunlock", {
"json": true,
"form": {
"pin": pin
}
}, function(err, response, body) {
if(!callback) {
return;
}
if(self._checkHttpError(err, response, callback)) {
return;
}
if(!body || typeof body.success !== 'boolean') {
return callback("Invalid response");
}
if(!body.success) {
return callback("Incorrect PIN");
}
callback();
}.bind(this));
};
SteamCommunity.prototype.getNotifications = function(callback) {
this.request.get("https://steamcommunity.com/actions/RefreshNotificationArea", function(err, response, body) {
if(self._checkHttpError(err, response, callback)) {
return;
}
var notifications = {
"comments": 0,
"items": 0,
"invites": 0,
"gifts": 0,
"chat": 0,
"trades": 0
};
var items = {
"comments": /(\d+) new comments?/,
"items": /(\d+) new items? in your inventory/,
"invites": /(\d+) new invites?/,
"gifts": /(\d+) new gifts?/,
"chat": /(\d+) unread chat messages?/,
"trades": /(\d+) new trade notifications?/
};
var match;
for(var i in items) {
if(match = body.match(items[i])) {
notifications[i] = parseInt(match[1], 10);
}
}
callback(null, notifications);
});
};
SteamCommunity.prototype.resetItemNotifications = function(callback) {
this.request.get("https://steamcommunity.com/my/inventory", function(err, response, body) {
if(!callback) {
return;
}
if(self._checkHttpError(err, response, callback)) {
return;
}
callback(null);
});
};
SteamCommunity.prototype.loggedIn = function(callback) {
this.request("https://steamcommunity.com/my", {"followRedirect": false}, function(err, response, body) {
if(err || (response.statusCode != 302 && response.statusCode != 403)) {
callback(err || new Error("HTTP error " + response.statusCode));
return;
}
if(response.statusCode == 403) {
callback(null, true, true);
return;
}
callback(null, !!response.headers.location.match(/steamcommunity\.com(\/(id|profiles)\/[^\/]+)\/?/), false);
});
};
SteamCommunity.prototype._checkCommunityError = function(html, callback) {
if(html.match(/<h1>Sorry!<\/h1>/)) {
var match = html.match(/<h3>(.+)<\/h3>/);
callback(new Error(match ? match[1] : "Unknown error occurred"));
return true;
}
return false;
};
SteamCommunity.prototype._myProfile = function(endpoint, form, callback) {
var self = this;
this.request("https://steamcommunity.com/my", {"followRedirect": false}, function(err, response, body) {
if(err || response.statusCode != 302) {
callback(err || "HTTP error " + response.statusCode);
return;
}
var match = response.headers.location.match(/steamcommunity\.com(\/(id|profiles)\/[^\/]+)\/?/);
if(!match) {
callback("Can't get profile URL");
return;
}
(form ? self.request.post : self.request)("https://steamcommunity.com" + match[1] + "/" + endpoint, form ? {"form": form} : {}, callback);
});
};
SteamCommunity.prototype._checkHttpError = function(err, response, callback) {
if(err) {
callback(err);
return true;
}
if(response.statusCode != 200) {
var error = new Error("HTTP error " + response.statusCode);
error.code = response.statusCode;
callback(error);
return true;
}
return false;
};
require('./classes/CMarketItem.js');
require('./classes/CMarketSearchResult.js');
require('./classes/CSteamGroup.js');
require('./classes/CSteamUser.js');
require('./components/chat.js');
require('./components/profile.js');

View File

@@ -1,7 +1,7 @@
{
"name": "steamcommunity",
"version": "0.1.0",
"description": "Facilitates logins to the Steam Communtiy website",
"version": "3.3.2",
"description": "Provides an interface for logging into and interacting with the Steam Community website",
"keywords": ["steam", "steam community"],
"homepage": "https://github.com/DoctorMcKay/node-steamcommunity",
"bugs": {
@@ -10,10 +10,13 @@
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/Doctor_McKay/node-steamcommunity.git"
"url": "https://github.com/DoctorMcKay/node-steamcommunity.git"
},
"dependencies": {
"request": "2.44.x",
"node-bignumber": "1.2.x"
"request": "^2.58.0",
"node-bignumber": "^1.2.1",
"steamid": "^0.3.0",
"xml2js": "^0.4.9",
"cheerio": "^0.19.0"
}
}