UNPKG

@octonary/mailgun-js

Version:

Simple Node.js helper module for Mailgun API. Forked to fix IE issues with ` character.

213 lines (171 loc) 5.73 kB
var tsscmp = require('tsscmp'); var crypto = require('crypto'); var Attachment = require('./attachment'); var Request = require('./request'); var builder = require('./build'); var resources = require('./schema').definitions; var mailgunExpirey = 15 * 60 * 1000; var mailgunHashType = 'sha256'; var mailgunSignatureEncoding = 'hex'; var Mailgun = function (options) { if(!options.apiKey){ throw new Error('apiKey value must be defined!'); } this.username = 'api'; this.apiKey = options.apiKey; this.publicApiKey = options.publicApiKey; this.domain = options.domain; this.auth = [this.username, this.apiKey].join(':'); this.mute = options.mute || false; this.timeout = options.timeout; this.host = options.host || 'api.mailgun.net'; this.endpoint = options.endpoint || '/v3'; this.protocol = options.protocol || 'https:'; this.port = options.port || 443; this.retry = options.retry || 1; if (options.proxy) { this.proxy = options.proxy; } this.options = { host: this.host, endpoint: this.endpoint, protocol: this.protocol, port: this.port, auth: this.auth, proxy: this.proxy, timeout: this.timeout, retry: this.retry }; this.mailgunTokens = {}; }; Mailgun.prototype.getDomain = function (method, resource) { var d = this.domain; //filter out API calls that do not require a domain specified if ((resource.indexOf('/routes') >= 0) || (resource.indexOf('/lists') >= 0) || (resource.indexOf('/address') >= 0) || (resource.indexOf('/domains') >= 0 )) { d = ''; } else if ((resource.indexOf('/messages') >= 0) && (method === 'GET' || method === 'DELETE')) { d = 'domains/' + this.domain; } return d; }; Mailgun.prototype.getRequestOptions = function (resource) { var o = this.options; // use public API key if we have it for the routes that require it if ((resource.indexOf('/address/validate') >= 0 || (resource.indexOf('/address/parse') >= 0)) && this.publicApiKey) { var copy = Object.assign({}, this.options); copy.auth = [this.username, this.publicApiKey].join(':'); o = copy; } return o; }; Mailgun.prototype.request = function (method, resource, data, fn) { var fullpath = resource; var domain = this.getDomain(method, resource); if (domain) { fullpath = '/'.concat(domain, resource); } var req = new Request(this.options); return req.request(method, fullpath, data, fn); }; Mailgun.prototype.post = function (path, data, fn) { var req = new Request(this.options); return req.request('POST', path, data, fn); }; Mailgun.prototype.get = function (path, data, fn) { var req = new Request(this.options); return req.request('GET', path, data, fn); }; Mailgun.prototype.delete = function (path, data, fn) { var req = new Request(this.options); return req.request('DELETE', path, data, fn); }; Mailgun.prototype.put = function (path, data, fn) { var req = new Request(this.options); return req.request('PUT', path, data, fn); }; Mailgun.prototype.validateWebhook = function (timestamp, token, signature) { var self = this; var adjustedTimestamp = parseInt(timestamp, 10) * 1000; var fresh = (Math.abs(Date.now() - adjustedTimestamp) < mailgunExpirey); if (!fresh) { if (!this.mute) { console.error('[mailgun] Stale Timestamp: this may be an attack'); console.error('[mailgun] However, this is most likely your fault\n'); console.error('[mailgun] run `ntpdate ntp.ubuntu.com` and check your system clock\n'); console.error('[mailgun] System Time: ' + new Date().toString()); console.error('[mailgun] Mailgun Time: ' + new Date(adjustedTimestamp).toString(), timestamp); console.error('[mailgun] Delta: ' + (Date.now() - adjustedTimestamp)); } return false; } if (this.mailgunTokens[token]) { if (!this.mute) { console.error('[mailgun] Replay Attack'); } return false; } this.mailgunTokens[token] = true; const tokenTimeout = setTimeout(function () { delete self.mailgunTokens[token]; }, mailgunExpirey + (5 * 1000)); tokenTimeout.unref(); return tsscmp( signature , crypto.createHmac(mailgunHashType, self.apiKey) .update(new Buffer(timestamp + token, 'utf-8')) .digest(mailgunSignatureEncoding) ); }; Mailgun.prototype.validate = function (address, isPrivate, opts, fn) { if (typeof opts === 'function') { fn = opts; opts = {}; } if (typeof isPrivate === 'object') { opts = isPrivate; isPrivate = false; } if (typeof isPrivate === 'function') { fn = isPrivate; isPrivate = false; opts = {}; } var resource = isPrivate ? '/address/private/validate' : '/address/validate'; var options = this.getRequestOptions(resource); var req = new Request(options); var data = Object.assign({}, { address: address }, opts); return req.request('GET', resource, data, fn); }; Mailgun.prototype.parse = function (addresses, isPrivate, opts, fn) { if (typeof opts === 'function') { fn = opts; opts = {}; } if (typeof isPrivate === 'object') { opts = isPrivate; isPrivate = false; } if (typeof isPrivate === 'function') { fn = isPrivate; isPrivate = false; opts = {}; } var resource = isPrivate ? '/address/private/parse' : '/address/parse'; var options = this.getRequestOptions(resource); var req = new Request(options); var data = Object.assign({}, { addresses: addresses }, opts); return req.request('GET', resource, data, fn); }; builder.build(Mailgun, resources); Mailgun.prototype.Attachment = Attachment; Mailgun.prototype.Mailgun = Mailgun; module.exports = function (options) { return new Mailgun(options); };