| 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.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.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; |
| |
| setTimeout(function () { |
| delete self.mailgunTokens[token]; |
| }, mailgunExpirey + (5 * 1000)); |
| |
| return tsscmp( |
| signature |
| , crypto.createHmac(mailgunHashType, self.apiKey) |
| .update(new Buffer(timestamp + token, 'utf-8')) |
| .digest(mailgunSignatureEncoding) |
| ); |
| }; |
| |
| builder.build(Mailgun, resources); |
| |
| Mailgun.prototype.Attachment = Attachment; |
| |
| Mailgun.prototype.Mailgun = Mailgun; |
| |
| module.exports = function (options) { |
| return new Mailgun(options); |
| }; |