UNPKG

steamauth

Version:

SteamGuard code generator and trade confirmations

1 lines 11.6 kB
"use strict";var util=require("util");var EventEmitter=require("events").EventEmitter;var crypto=require("crypto");var _=require("underscore");var base32=require("rfc-3548-b32");var request=require("request");var async=require("async");var NodeRSA=require("node-rsa");var cheerio=require("cheerio");var bunyan=require("bunyan");var SteamAuth=function e(t,r){var a=this;EventEmitter.call(this);if(typeof t==="function"&&!r){r=t;t={}}if(!t){t={}}if(typeof t==="string"){t={secret:t}}if(t.loglevel){e.Logger.level(t.loglevel)}a.session={};a.auth={};if(t.shared_secret){_.extend(a.auth,t)}else if(t.secret){_.extend(a.auth,t);a.auth.shared_secret=decodeSecretToBuffer(t.secret,t.encoding).toString("base64")}if(!t.time&&(typeof t.sync==="undefined"||t.sync)){if(t.sync===true){e.Offset=0}e.Sync(function(e,t){if(e){a.emit("error",e);if(r){r(e)}return}if(r){r(null,t)}a.emit("ready")})}else{if(r){r()}a.emit("ready")}};util.inherits(SteamAuth,EventEmitter);SteamAuth.Logger=bunyan.createLogger({name:"SteamAuth"});SteamAuth.Logger.level("warn");SteamAuth.INTERVAL_PERIOD_MS=3e4;SteamAuth.INT64_BUFFER_SIZE=8;SteamAuth.MAX_INT32=Math.pow(2,32);SteamAuth.DIGITS=5;SteamAuth.ALPHABET=["2","3","4","5","6","7","8","9","B","C","D","F","G","H","J","K","M","N","P","Q","R","T","V","W","X","Y"];SteamAuth.SYNC_URL="https://api.steampowered.com/ITwoFactorService/QueryTime/v0001";SteamAuth.COMMUNITY_BASE="https://steamcommunity.com";SteamAuth.WEBAPI_BASE="https://api.steampowered.com";SteamAuth.API_GETWGTOKEN=SteamAuth.WEBAPI_BASE+"/IMobileAuthService/GetWGToken/v0001";SteamAuth.Offset=0;SteamAuth.Sync=function(e){SteamAuth.Syncing=true;if(SteamAuth.Offset){setTimeout(function(){e(null,SteamAuth.Offset)},10);return}request({url:SteamAuth.SYNC_URL,method:"POST",headers:{accept:"*/*"},json:true},function(t,r,a){if(r.statusCode!=200){return e({message:"Non 200 response from Steam"})}if(!a||!a.response||!a.response.server_time){return e({message:"Invalid time response from Steam"})}var i=parseInt(a.response.server_time)*1e3;var o=SteamAuth.Offset=(new Date).getTime()-i;e(null,o)})};SteamAuth.request=function(e,t){if(!e.headers){e.headers={}}_.extend(e.headers,{accept:"text/javascript, text/html, application/xml, text/xml, */*","User-Agent":"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",Referrer:SteamAuth.COMMUNITY_BASE,"X-Requested-With":"com.valvesoftware.android.steam.community"});if(!e.cookies){e.cookies=request.jar()}var r={url:e.url,method:e.method||"GET",headers:e.headers,jar:e.cookies,form:e.method=="POST"?e.data:null,qs:e.method=="GET"?e.data:null,json:!!e.json};SteamAuth.Logger.debug("Request",r);request(r,function(e,a,i){if(e){SteamAuth.Logger.error("Response Error",a,i)}else{SteamAuth.Logger.debug("Response",r,a,i)}return t(e,a,i)})};SteamAuth.prototype.login=function(e,t){var r=this;if(!e){var a={message:"opts parameter is required"};r.emit("error",a);if(t){t(a)}return}var i=r.session||{};i.error=null;var o=e.username||i.username;var n=e.password||i.password;if(e.deviceid){r.auth.deviceid=e.deviceid}var s=i.cookies=i.cookies||request.jar();s.setCookie(request.cookie("mobileClientVersion=3067969+%282.1.3%29"),SteamAuth.COMMUNITY_BASE+"/");s.setCookie(request.cookie("mobileClient=android"),SteamAuth.COMMUNITY_BASE+"/");s.setCookie(request.cookie("steamid="),SteamAuth.COMMUNITY_BASE+"/");s.setCookie(request.cookie("steamLogin="),SteamAuth.COMMUNITY_BASE+"/");s.setCookie(request.cookie("Steam_Language=english"),SteamAuth.COMMUNITY_BASE+"/");s.setCookie(request.cookie("dob="),SteamAuth.COMMUNITY_BASE+"/");async.series([function(e){SteamAuth.Sync(e)},function(e){if(i.oauth){return e()}SteamAuth.request({url:SteamAuth.COMMUNITY_BASE+"/login?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client",cookies:s},function(t,r){return e(t)})},function(e){if(i.oauth){return e()}SteamAuth.request({url:SteamAuth.COMMUNITY_BASE+"/login/getrsakey",method:"POST",data:{username:o},cookies:s,json:true},function(t,r,a){if(t){return e(t)}if(!a.success){return e({message:"Unknown user "+o})}i.timestamp=a.timestamp;i.publicpem=createRsaPublicPem(a.publickey_mod,a.publickey_exp);e()})},function(t){if(i.oauth){return t()}var a=new NodeRSA(i.publicpem,"public",{encryptionScheme:"pkcs1"});var u=a.encrypt(n,"base64","utf8");var c=e.twofactorcode||"";if(!c&&r.auth&&r.auth.shared_secret){c=r.calculateCode()}var m=SteamAuth.request({url:SteamAuth.COMMUNITY_BASE+"/login/dologin/",method:"POST",data:{username:o,password:u,twofactorcode:c,emailauth:e.emailauthtext||"",loginfriendlyname:"#login_emailauth_friendlyname_mobile",captchagid:e.captchaid||"-1",captcha_text:e.captchatext||"enter above characters",emailsteamid:e.emailauthtext?i.steamid||"":"",rsatimestamp:i.timestamp,remember_login:"false",oauth_client_id:"DE45CD61",oauth_scope:"read_profile write_profile read_client write_client",donotache:(new Date).getTime()},cookies:s,json:true},function(e,r,a){if(e){return t(e)}if(!a){return t({message:"Invalid login response"})}if(a.emailsteamid){i.steamid=a.emailsteamid}if(!a.login_complete||!a.oauth){if(a.captcha_needed){var o=a.captcha_gid;var n=SteamAuth.COMMUNITY_BASE+"/public/captcha.php?gid="+o;e=new Error("Need captcha for "+n);e.captchaid=o;e.captchaurl=n;return t(e)}if(a.emailauth_needed){return t(new Error("Need email auth code "+a.emaildomain||""))}if(a.requires_twofactor){return t(new Error("Need 2FA"))}return t(new Error(a.message||"Invalid login"))}try{i.oauth=JSON.parse(a.oauth)}catch(s){t(s)}if(!i.oauth||!i.oauth.oauth_token){return t(new Error("Expected OAUTH token"))}if(i.oauth.steamid){i.steamid=i.oauth.steamid}t()})}],function(e){if(e){return t(e)}t(null,i)})};SteamAuth.prototype.refresh=function(e){var t=this;if(!t.session||!t.session.oauth){return e(null,false)}SteamAuth.request({url:SteamAuth.API_GETWGTOKEN,method:"POST",data:{access_token:t.session.oauth.oauth_token},cookies:t.session.cookies,json:true},function(r,a,i){if(r){return e(r)}if(!i||!i.response){return e(null,false)}t.session.cookies.setCookie(request.cookie("steamLogin="+t.session.steamid+"%7C%7C"+i.response.token),SteamAuth.COMMUNITY_BASE+"/");t.session.cookies.setCookie(request.cookie("steamLoginSecure="+t.session.steamid+"%7C%7C"+i.response.token_secure),SteamAuth.COMMUNITY_BASE+"/");e(null,true)})};SteamAuth.prototype.getTradeConfirmations=function(e){var t=this;if(!t.session||!t.session.oauth){return e({message:"not logged in"})}var r="conf";var a=Math.floor(((new Date).getTime()+(SteamAuth.Offset||0))/1e3);var i=createTimeHash(a,r,t.auth.identity_secret);SteamAuth.request({url:SteamAuth.COMMUNITY_BASE+"/mobileconf/conf",method:"GET",data:{p:t.auth.deviceid,a:t.session.steamid,k:i,t:a,m:"android",tag:r},cookies:t.session.cookies,json:true},function(t,r,a){if(t){return e(t)}var i=[];var o=cheerio.load(a);o(".mobileconf_list_entry").each(function(){var e=o(this);var t=e.attr("data-confid");if(t){var r={id:t};r.key=e.attr("data-key");r.image=o(".mobileconf_list_entry_icon img",e).attr("src");var a=o(".mobileconf_list_entry_description > div",e);r.details=a.length>0?a.eq(0).html():"";r.traded=a.length>1?a.eq(1).html():"";r.when=a.length>2?a.eq(2).html():"";i.push(r)}});SteamAuth.Logger.info("GetTradeConfirmations",i);e(null,i)})};SteamAuth.prototype.rejectTradeConfirmation=function(e,t,r){this.sendConfirmation(e,t,"cancel",r)};SteamAuth.prototype.acceptTradeConfirmation=function(e,t,r){this.sendConfirmation(e,t,"allow",r)};SteamAuth.prototype.sendConfirmation=function(e,t,r,a){var i=this;if(!i.session||!i.session.oauth){return a({message:"not logged in"})}var o=Math.floor(((new Date).getTime()+(SteamAuth.Offset||0))/1e3);var n=createTimeHash(o,r,i.auth.identity_secret);SteamAuth.request({url:SteamAuth.COMMUNITY_BASE+"/mobileconf/ajaxop",method:"GET",data:{op:r,p:i.auth.deviceid,a:i.session.steamid,k:n,t:o,m:"android",tag:r,cid:e,ck:t},cookies:i.session.cookies,json:true},function(t,i,o){if(t){return a(t)}if(!o.success){return a(new Error("Unable to "+r+" "+e))}a()})};SteamAuth.prototype.getTradeConfirmation=function(e,t){var r=this;if(!r.session||!r.session.oauth){return t({message:"not logged in"})}var a="details"+e;var i=Math.floor(((new Date).getTime()+(SteamAuth.Offset||0))/1e3);var o=createTimeHash(i,a,r.auth.identity_secret);SteamAuth.request({url:SteamAuth.COMMUNITY_BASE+"/mobileconf/details/"+e,method:"GET",data:{p:r.auth.deviceid,a:r.session.steamid,k:o,t:i,m:"android",tag:a},cookies:r.session.cookies,json:true},function(r,a,i){if(r){return t(r)}if(!i.success){return t(new Error("Unknown Conf "+e))}var o=cheerio.load(i.html);var n=o(".mobileconf_trade_area");if(!n.length){return t(new Error("Cannot find trade"))}var s={partner:{},items:[],receiving:[]};var u=o(".trade_partner_header",n);s.partner.name=o(".trade_partner_headline_sub a",u).html();s.partner.steamid=/[\s\S]*\/profiles\/([\s\S]*)/i.exec(o(".trade_partner_headline_sub a",u).attr("href"));t(null,s,i.html)})};SteamAuth.calculateCode=function(e,t){if(typeof e==="string"){e={secret:e}}if(t){e.time=t}var r=new SteamAuth({sync:!e.time});return r.calculateCode(e)};SteamAuth.prototype.calculateCode=function(e,t){var r=this;if(!e){e={}}else if(typeof e==="string"){e={shared_secret:decodeSecretToBuffer(e,"base32")}}if(t){e.time=t}var a;if(e.secret){a=decodeSecretToBuffer(e.secret,e.encoding||"base32")}else if(e.shared_secret){a=decodeSecretToBuffer(e.shared_secret,e.encoding||"base64")}else if(r.auth){a=decodeSecretToBuffer(r.auth.shared_secret,"base64")}else{var i={message:"No secret key defined"};r.emit("error",i);throw i}t=e.time;if(!t){t=(new Date).getTime()+SteamAuth.Offset}var o=Math.floor(t/SteamAuth.INTERVAL_PERIOD_MS);var n=new Buffer(SteamAuth.INT64_BUFFER_SIZE);n.writeUInt32BE(Math.floor(o/SteamAuth.MAX_INT32),0);n.writeUInt32BE(o%SteamAuth.MAX_INT32,4);var s=crypto.createHmac("sha1",a);var u=s.update(n).digest();var c=u[19]&15;var m=u.readUInt32BE(c)&2147483647;var h="";for(var f=0;f<SteamAuth.DIGITS;f++){h+=SteamAuth.ALPHABET[m%SteamAuth.ALPHABET.length];m=Math.floor(m/SteamAuth.ALPHABET.length)}return h};function decodeSecretToBuffer(e,t){if(!e||e instanceof Buffer){return e}if(!t){if(/^([ABCDEF0-9]{2})+$/i.test(e)){t="hex"}else if(/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/.test(e)){t="base32"}else{t="base64"}}if(t=="hex"){return new Buffer(e,"hex")}else if(t=="base32"){return base32.decode(e)}else if(t=="base64"){return new Buffer(e,"base64")}else{throw{message:"Unknown encoding "+t}}}function createRsaPublicPem(e,t){function r(e){var t=e[0];if(t>="8"&&t<="9"||t>="a"&&t<="f"||t>="A"&&t<="F"){return"00"+e}else{return e}}function a(e){var t=e.toString(16);if(t.length%2===0){return t}else{return"0"+t}}function i(e){if(e<=127){return a(e)}else{var t=a(e);var r=128+t.length/2;return a(r)+t}}e=r(e);t=r(t);var o=e.length/2;var n=t.length/2;var s=i(o);var u=i(n);var c="30"+i(o+n+s.length/2+u.length/2+2)+"02"+s+e+"02"+u+t;var m="30 0d "+"06 09 2a 86 48 86 f7 0d 01 01 01"+"05 00 "+"03"+i(c.length/2+1)+"00"+c;m=m.replace(/ /g,"");var h="30"+i(m.length/2)+m;h=h.replace(/ /g,"");var f=new Buffer(h,"hex");var l=f.toString("base64");return"-----BEGIN PUBLIC KEY-----\n"+l.match(/.{1,64}/g).join("\n")+"\n-----END PUBLIC KEY-----\n"}function createTimeHash(e,t,r){var a=new Buffer(r,"base64");var i=8;if(t){i+=Math.min(32,t.length)}var o=new Buffer(i);o.writeUInt32BE(Math.floor(e/SteamAuth.MAX_INT32),0);o.writeUInt32BE(e%SteamAuth.MAX_INT32,4);if(t){o.write(t,8,i-8,"utf8")}var n=crypto.createHmac("sha1",a);var s=n.update(o).digest();return s.toString("base64")}module.exports=SteamAuth;