diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4328ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +.DS_Store +repl.js diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fcc5a9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2015 Steven White +All Rights Reserved. + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf90d59 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# hover-api + +Hover DNS api client, inspired completely by [https://gist.github.com/dankrause/5585907](https://gist.github.com/dankrause/5585907). + +## Usage + +```javascript +var hover = require('hover-api')('username', 'password'); + +hover.getAllDomains(function (err, domains) { + console.log(domains); +}); +``` + +## API + +* getAllDomains(cb) +* getAllDns(cb) +* getDomain(domain, cb) +* getDomainDns(domain, cb) +* createARecord (domain, subdomain, ip, cb) +* createMXRecord (domain, subdomain, priority, ip, cb) +* updateDomainDns (dns, ip, cb) +* removeDns (dns, cb) + +## License + +See [LICENSE](LICENSE) diff --git a/index.js b/index.js new file mode 100644 index 0000000..6473eee --- /dev/null +++ b/index.js @@ -0,0 +1,225 @@ +/** + * index.js + * Entry point into hover-api + * + * (C) Steven White 2015 + */ + +var request = require('request'), + _ = require('lodash'); + +module.exports = function (username, password) { + + // Base url for all hover api requests + var baseUrl = 'https://www.hover.com/api'; + + // Captured from cookie in hover authentication request. + var cookies = request.jar(); + + // Note whether login has occured. + // A successful login generates a "hoverauth" cookie + var _loggedin = false; + + // Create request wrapper, enabling json and cookies + var r = request.defaults({ + jar: cookies, + json: true + }); + + /** + * Retrieve list of all domains in account + * + * @param {Function} cb + * @api public + */ + function getAllDomains (cb) { + _hoverRequest('GET', '/domains', cb); + } + + /** + * Retrieve list of all dns records in account + * + * @param {Function} cb + * @api public + */ + function getAllDns (cb) { + _hoverRequest('GET', '/dns', cb); + } + + /** + * Retrieve individual domain in account + * + * @param {String} domain Domain identifier + * @param {Function} cb + * @api public + */ + function getDomain (domain, cb) { + _hoverRequest('GET', '/domains/' + domain, cb); + } + + /** + * Retrieve list of all dns records for particular domain + * + * @param {String} domain Domain identifier + * @param {Function} cb + * @api public + */ + function getDomainDns (domain, cb) { + _hoverRequest('GET', '/domains/' + domain + '/dns', cb); + } + + /** + * Create a new A record under the specified domain + * + * @param {String} domain Domain identifier + * @param {String} subdomain Subdomain of record + * @param {String} ip IP Address of record + * @param {Function} cb + * @api public + */ + function createARecord (domain, subdomain, ip, cb) { + var body = { + name: subdomain, + type: 'A', + content: ip + }; + _hoverRequest('POST', '/domains/' + domain + '/dns', body, cb); + } + + /** + * Create a new MX record under the specified domain + * + * @param {String} domain Domain identifier + * @param {String} subdomain Subdomain of record + * @param {String} priority Priority of record + * @param {String} ip IP Address of record + * @param {Function} cb + * @api public + */ + function createMXRecord (domain, subdomain, priority, ip, cb) { + var body = { + name: subdomain, + type: 'MX', + content: [priority, ip].join(' ') + }; + _hoverRequest('POST', '/domains/' + domain + '/dns', body, cb); + } + + /** + * Update an existing domain record + * + * @param {String} dns DNS identifier + * @param {String} ip New IP Address of record + * @param {Function} cb + * @api public + */ + function updateDomainDns (dns, ip, cb) { + var body = { + content: ip + }; + _hoverRequest('PUT', '/dns/' + dns, body, cb); + } + + /** + * Remove an existing dns record + * + * @param {String} dns DNS identifier + * @param {Function} cb + * @api public + */ + function removeDns (dns, cb) { + _hoverRequest('DELETE', '/dns/' + dns, cb); + } + + /** + * Proxy request to hover API. Will issue login request if not + * previously generated. + * + * @param {String} method + * @param {String} path + * @param {Function} cb + * @api private + */ + function _hoverRequest (method, path, body, cb) { + // Check if previously logged in + if (_loggedin) return _hoverApiRequest(method, path, body, cb); + + // Issue login request with provided username / password + r({ + uri: baseUrl + '/login', + body: 'username=' + username + '&password=' + password, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }, _rCallback(function (err) { + if (err) return cb(err); + + // Note logged in / forward request + _loggedin = true; + _hoverApiRequest(method, path, body, cb); + })); + } + + /** + * Issue request to hover api. + * + * @param {String} method + * @param {String} path + * @param {Object} [body] + * @param {Function} cb + * @api private + */ + function _hoverApiRequest (method, path, body, cb) { + // Check body provided + if (typeof body === 'function') { + cb = body; + body = null; + } + + // Default options + var options = { + method: method, + uri: baseUrl + path + }; + + // Add body if provided + if (body) options.body = body; + + // Issue request + r(options, _rCallback(function (err, data) { + if (err) return cb(err); + + // Pull out property name + var key = _.without(_.keys(data), 'succeeded'); + cb(null, data[key]); + })); + } + + /** + * Request callback abstraction to deliver http or connection error. + * + * @param {Function} cb + * @return {Function} + * @api private + */ + function _rCallback (cb) { + return function (err, res, data) { + if (err) return cb(err); + if (!res || res.statusCode > 400) return cb(data); + + cb(null, data); + }; + } + + // Expose API + return { + getAllDomains: getAllDomains, + getAllDns: getAllDns, + getDomain: getDomain, + getDomainDns: getDomainDns, + createARecord: createARecord, + createMXRecord: createMXRecord, + updateDomainDns: updateDomainDns, + removeDns: removeDns + }; +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..8aca3cd --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "hover-api", + "version": "1.0.0", + "description": "Hover DNS API Client", + "main": "index.js", + "scripts": { + "test": "mocha -R spec" + }, + "repository": { + "type": "git", + "url": "github.com:swhite24/hover-api" + }, + "keywords": [ + "hover", + "hover.com", + "dns", + "api" + ], + "author": "Steven White (http://stevenwhite.com/)", + "license": "MIT", + "bugs": { + "url": "https://github.com/swhite24/hover-api/issues" + }, + "homepage": "https://github.com/swhite24/hover-api", + "devDependencies": { + "mocha": "^2.1.0", + "should": "^4.5.1" + }, + "dependencies": { + "lodash": "^2.4.1", + "request": "^2.51.0", + "tough-cookie": "^0.12.1" + } +}