diff --git a/components/webapi.js b/components/webapi.js index a138ee5..ad495a4 100644 --- a/components/webapi.js +++ b/components/webapi.js @@ -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(/

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 (]+>)?Steam Guard Mobile Authenticator/)) { + return callback(new Error('Steam Guard Mobile Authenticator required to create a Steam Web API key')); } - var match = body.match(/

Key: ([0-9A-F]+)<\/p>/); - if(match) { + if (body.match(/

Access Denied<\/h2>/)) { + return callback(new Error('Access Denied')); + } + + let match = body.match(/

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"); + }); }; /**