├── .eslintrc.js ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── discord ├── botlist.js ├── cogs.js ├── cogs │ ├── email.js │ ├── fun.js │ └── system.js ├── handler.js └── index.js ├── docs ├── automacord.html ├── browser.js ├── css │ └── index.css ├── gdpr │ ├── README.md │ ├── data.json │ └── gdpr.zip ├── how.html ├── img │ ├── DiscordMail.png │ ├── discordmail.svg │ ├── favicon.png │ └── stack.jpg ├── index.html ├── js │ └── fake_discordbots.js ├── keybase.txt └── plaintext.xcf ├── example_config ├── discord.json ├── emails.json ├── mailserver.json └── modes.json ├── helpers ├── decode.js └── encode.js ├── locales └── en-gb.json ├── mailserver └── index.js ├── package-lock.json ├── package.json └── test.ps1 /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'airbnb-base' 3 | }; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | config 3 | aaa 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.autoIndent": false, 3 | "editor.tabSize": 2 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DiscordMail for Webhooks 2 | 3 | DiscordMail webhooks... it's like webhooks for DiscordMail! 4 | 5 | ## Thanks 6 | [AlexFlipnote](https://github.com/AlexFlipnote) / [**ModestaCSS**](https://github.com/AlexFlipnote/ModestaCSS) 7 | [kawanet](https://github.com/kawanet) / [**int64-buffer**](https://github.com/kawanet/int64-buffer) 8 | [nodemailer](https://github.com/nodemailer) / [**mailparser**](https://github.com/nodemailer/mailparser) 9 | [nodemailer](https://github.com/nodemailer) / [**smtp-server**](https://github.com/nodemailer/smtp-server) 10 | [request](https://github.com/request) / [**request**](https://github.com/request/request) 11 | 12 | ## Hosting 13 | 1. Fill in the configuration in `index.js` 14 | 2. `npm i` 15 | 3. `npm run` 16 | 17 | You may want to obtain a certificate from Let's Encrypt. 18 | 19 | ## Recommended Setup 20 | 1. For each domain, set up a CNAME record to `mss.ovh`, at `mail.[domain]`. For example, `mail.discordbots.co.uk` 21 | 2. Add an MX record pointing at `mail.mss.ovh` 22 | 3. Using `certbot-auto`, use the certonly function to create a single certificate with every domain that you may have. 23 | - Dry run: `./certbot-auto certonly -d mail.mss.ovh -d mail.discordbots.co.uk -d mail.discordbots.uk -d discordmail.com --dry-run` 24 | - Actual run: `./certbot-auto certonly -d mail.mss.ovh -d mail.discordbots.co.uk -d mail.discordbots.uk -d discordmail.com` 25 | 4. After this completes, copy the certificate location and edit the `config/mailserver.json` file. 26 | -------------------------------------------------------------------------------- /discord/botlist.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | const config = require('./../config/discord.json'); 3 | 4 | module.exports = (client) => { 5 | console.log('Posting count...'); 6 | if (config.api.botsdiscordpw) { 7 | console.log('botsdiscordpw'); 8 | fetch(`https://discord.bots.gg/api/v1/bots/${client.user.id}/stats`, { 9 | method: 'post', 10 | body: JSON.stringify({ 11 | guildCount: client.guilds.size 12 | }), 13 | headers: { 14 | 'Content-Type': 'application/json', 15 | Authorization: config.api.botsdiscordpw 16 | } 17 | }) 18 | .then(res => res.json()) 19 | .then(data => console.log(data)) 20 | .catch((err) => { 21 | console.log(err); 22 | }); 23 | } 24 | if (config.api.ls) { 25 | console.log('ls'); 26 | fetch(`https://ls.terminal.ink/api/v2/bots/${client.user.id}`, { 27 | method: 'post', 28 | body: JSON.stringify({ 29 | bot: { 30 | count: client.guilds.size 31 | } 32 | }), 33 | headers: { 34 | 'Content-Type': 'application/json', 35 | Authorization: config.api.ls 36 | } 37 | }) 38 | .then(res => res.json()) 39 | .then(data => console.log(data)) 40 | .catch((err) => { 41 | console.log(err); 42 | }); 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /discord/cogs.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const commands = {}; 4 | const categories = {}; 5 | 6 | // Register valid commands from "cogs" 7 | fs.readdir('./cogs', (err, items) => { 8 | items.forEach((item) => { 9 | const file = item.replace(/\.js/g, ''); 10 | const cog = require(`./cogs/${file}`); // eslint-disable-line global-require, import/no-dynamic-require 11 | if (Array.isArray(cog)) { 12 | categories[file] = cog; 13 | cog.forEach((com) => { 14 | com.aliases.forEach((alias) => { 15 | if (commands[alias]) { 16 | throw new Error(`Alias ${alias} from ${file} was already assigned to another command!`); 17 | } else { 18 | console.log(`Loading ${com.name} as ${alias} from ${file}`); 19 | commands[alias] = com; 20 | } 21 | }); 22 | }); 23 | } else { 24 | console.error(`${file} does not have an array of commands! Ignoring.`); 25 | } 26 | }); 27 | }); 28 | 29 | module.exports = { commands, categories }; 30 | -------------------------------------------------------------------------------- /discord/cogs/email.js: -------------------------------------------------------------------------------- 1 | const decode = require('./../../helpers/decode'); 2 | const encode = require('./../../helpers/encode'); 3 | const modes = require('./../../config/modes.json'); 4 | const config = require('./../../config/discord.json'); 5 | 6 | module.exports = [{ 7 | aliases: [ 8 | 'encode', 9 | ], 10 | name: 'encode', 11 | uses: 1, 12 | admin: 0, 13 | command: (message) => { 14 | const encoded = encode(message.mss.input); 15 | 16 | if (encoded) { 17 | message.channel.createMessage(message.t('register_email', { 18 | email: `${encoded}@${config.domain}`, 19 | })); 20 | } else { 21 | message.channel.createMessage(message.t('encode_invalid')); 22 | } 23 | }, 24 | }, { 25 | aliases: [ 26 | 'decode', 27 | ], 28 | name: 'decode', 29 | uses: 1, 30 | admin: 0, 31 | command: (message) => { 32 | const decoded = decode(message.mss.input); 33 | 34 | if (decoded) { 35 | message.channel.createMessage(`**URL:** ${decoded.hidden ? 'Protected' : decoded.decoded}\n**${message.t('decode_mode')}** ${message.t(modes[decoded.middle]) || message.t('mode_unknown')}`); 36 | } else { 37 | message.channel.createMessage(message.t('decode_invalid')); 38 | } 39 | }, 40 | }, { 41 | aliases: [ 42 | 'register', 43 | ], 44 | name: 'register', 45 | uses: 1, 46 | admin: 1, 47 | command: (message, client) => { 48 | if (message.channel.guild) { 49 | const self = message.channel.guild.members.get(client.user.id); 50 | const overwrites = message.channel.permissionOverwrites.get(client.user.id); 51 | 52 | if (!self) { 53 | message.channel.createMessage(message.t('register_err_self')); 54 | } else if (self.permission.has('administrator') || self.permission.has('manageWebhooks') || (overwrites && overwrites.has('manageWebhooks'))) { 55 | message.channel.createWebhook({ 56 | name: config.name, 57 | avatar: 'https://webhooks.discordmail.com/img/DiscordMail.png', 58 | }, `${message.author.username} (${message.author.id})`) 59 | .then((webhook) => { 60 | const encoded = encode(`${webhook.id}/${webhook.token}`); 61 | message.channel.createMessage(message.t('register_email', { 62 | email: `${encoded}@${config.domain}`, 63 | })); 64 | }); 65 | } else { 66 | message.channel.createMessage(`${message.t('register_err_perms')}\n${config.url.website}`); 67 | } 68 | } else { 69 | message.channel.createMessage(message.t('register_err_guild')); 70 | } 71 | }, 72 | }]; 73 | -------------------------------------------------------------------------------- /discord/cogs/fun.js: -------------------------------------------------------------------------------- 1 | const request = require('request'); 2 | 3 | const MEI = 'https://www.reddit.com/r/wholesomeyuri/.json'; 4 | const EMOJI = '<:blobcatreeeeeee:436990758973734922>'; 5 | const select = data => data[Math.floor(Math.random() * data.length)]; 6 | 7 | let meiTimestamp = 0; 8 | let meiData = null; 9 | 10 | const meiUpdate = () => new Promise((resolve, reject) => { 11 | request({ 12 | uri: MEI, 13 | json: true, 14 | }, (err, res, body) => { 15 | console.log('Updating Mei Reddit Data'); 16 | if (body.kind === 'Listing') { 17 | // Get posts that are kind "t3" and not nsfw 18 | const posts = body.data.children 19 | .filter(post => post.kind === 't3') 20 | .filter(post => post.data.over_18 === false); 21 | 22 | // Limit bot to request every 30 minutes 23 | meiTimestamp = Date.now() + (1000 * 60 * 30); 24 | resolve(posts); 25 | } else { 26 | reject(); 27 | } 28 | }); 29 | }); 30 | 31 | module.exports = [{ 32 | aliases: [ 33 | 'mei', 34 | ], 35 | name: 'mei', 36 | uses: 1, 37 | admin: 0, 38 | command: async (message) => { 39 | // If the data has expired, request more data 40 | if (meiTimestamp < Date.now()) { 41 | // Try and request new data 42 | try { 43 | // Update the data and create a message 44 | meiData = await meiUpdate(message); 45 | message.channel.createMessage(select(meiData).data.url); 46 | } catch (e) { 47 | // Fiddlesticks 48 | message.channel.createMessage(EMOJI + message.t('mei_no_list')); 49 | } 50 | } else { 51 | // Create a message 52 | message.channel.createMessage(select(meiData).data.url); 53 | } 54 | }, 55 | }]; 56 | -------------------------------------------------------------------------------- /discord/cogs/system.js: -------------------------------------------------------------------------------- 1 | const cogs = require('./../cogs'); 2 | const { exec } = require('child_process'); 3 | const os = require('os'); 4 | 5 | const hardwareinfo = `(${os.arch()}) ${os.cpus()[0].model} @ ${os.cpus()[0].speed} MHz`; 6 | const softwareinfo = `[${os.type()}] ${os.release()}`; 7 | 8 | module.exports = [{ 9 | aliases: [ 10 | 'ping', 11 | ], 12 | name: 'ping', 13 | uses: 1, 14 | admin: 0, 15 | command: (message, client) => { 16 | if (client.guildShardMap) { 17 | let s = 0; 18 | 19 | if (message.channel.guild) { 20 | s = client.guildShardMap[message.channel.guild.id]; 21 | } 22 | 23 | message.channel.createMessage(`\`\`\`\n${client.shards.map(shard => `${s === shard.id ? '>' : ' '}Shard ${shard.id} | ${shard.latency}ms`).join('\n')}\n\`\`\``); 24 | } else { 25 | message.channel.createMessage(message.t('ping_nomap')); 26 | } 27 | }, 28 | }, { 29 | aliases: [ 30 | 'eval', 31 | ], 32 | name: 'eval', 33 | uses: 1, 34 | admin: 3, 35 | command: (message) => { 36 | eval(message.mss.input); // eslint-disable-line no-eval 37 | }, 38 | }, { 39 | aliases: [ 40 | 'exec', 41 | ], 42 | name: 'exec', 43 | uses: 1, 44 | admin: 3, 45 | command: (message) => { 46 | if (message.mss.input) { 47 | exec(message.mss.input, (error, stdout, stderr) => { 48 | let output = ''; 49 | 50 | if (stdout) { 51 | output += '=== stdout ===\n'; 52 | output += `${stdout.replace(/`/g, '\'')}\n`; 53 | } 54 | 55 | if (stderr) { 56 | output += '=== stderr ===\n'; 57 | output += `${stderr.replace(/`/g, '\'')}\n`; 58 | } 59 | 60 | message.channel.createMessage(`\n${message.t('exec_output')}\n\`\`\`\n${output}\`\`\``); 61 | }); 62 | } 63 | }, 64 | }, { 65 | aliases: [ 66 | 'help', 67 | ], 68 | name: 'help', 69 | uses: 3, 70 | admin: 0, 71 | command: (message) => { 72 | if (message.mss.input && cogs.commands[message.mss.input]) { 73 | const command = cogs.commands[message.mss.input]; 74 | const fields = []; 75 | for (let i = 1; i <= command.uses; i += 1) { 76 | fields.push({ 77 | name: message.t(`${command.name}_${i}_in`, { prefix: message.mss.prefix, command: command.name }), 78 | value: message.t(`${command.name}_${i}_out`), 79 | }); 80 | } 81 | 82 | message.channel.createMessage({ 83 | embed: { 84 | title: message.t(command.name), 85 | description: message.t(`${command.name}_desc`), 86 | fields, 87 | }, 88 | }); 89 | } else if (message.mss.input && cogs.categories[message.mss.input]) { 90 | message.channel.createMessage({ 91 | embed: { 92 | title: message.t(message.mss.input), 93 | fields: cogs.categories[message.mss.input] 94 | .filter(command => message.mss.admin >= command.admin) 95 | .map(command => ({ 96 | name: command.aliases[0], 97 | value: message.t(`${command.name}_desc`), 98 | })), 99 | }, 100 | }); 101 | } else if (!message.mss.input) { 102 | // If there is no input, make a "field" for each category to embed, with a list of commands 103 | const fields = Object.keys(cogs.categories).map(category => ({ 104 | name: `\`${category}\` - ${message.t(category)}`, 105 | value: cogs.categories[category] 106 | .filter(command => message.mss.admin >= command.admin) 107 | .map(command => command.aliases[0]) 108 | .map(name => `\`${name}\``) 109 | .join(', '), 110 | })); 111 | 112 | message.channel.createMessage({ 113 | embed: { 114 | title: message.t('help_menu_title'), 115 | description: message.t('help_menu_description'), 116 | fields, 117 | footer: { 118 | text: message.t('help_menu_footer', { 119 | prefix: message.mss.prefix, 120 | command: message.mss.command 121 | }), 122 | }, 123 | }, 124 | }); 125 | } else { 126 | message.channel.createMessage(message.t('help_invalid')); 127 | } 128 | }, 129 | }, { 130 | aliases: [ 131 | 'info', 132 | ], 133 | name: 'info', 134 | uses: 1, 135 | admin: 0, 136 | command: (message, client) => { 137 | const embed = { 138 | embed: { 139 | fields: [ 140 | { 141 | name: message.t('info_nodejs'), 142 | value: process.version, 143 | inline: true, 144 | }, 145 | { 146 | name: message.t('info_guilds'), 147 | value: client.guilds.size, 148 | inline: true, 149 | }, 150 | { 151 | name: message.t('info_pid'), 152 | value: process.pid, 153 | inline: true, 154 | }, 155 | { 156 | name: message.t('info_hard'), 157 | value: hardwareinfo, 158 | }, 159 | { 160 | name: message.t('info_soft'), 161 | value: softwareinfo, 162 | }, 163 | { 164 | name: message.t('info_licence'), 165 | value: message.t('info_licencedesc', { name: message.t('name') }), 166 | }, 167 | ], 168 | }, 169 | }; 170 | 171 | message.channel.createMessage(embed); 172 | }, 173 | }]; 174 | -------------------------------------------------------------------------------- /discord/handler.js: -------------------------------------------------------------------------------- 1 | const config = require('./../config/discord.json'); 2 | const { commands } = require('./cogs'); 3 | const client = require('./'); 4 | const i18n = require('i18n'); 5 | 6 | const prefixes = config.discord.prefix; 7 | 8 | /* 9 | * Modified Eris Code - https://github.com/abalabahaha/eris 10 | * Allows me to clean any message content 11 | */ 12 | const clean = (message, content) => { 13 | let cleanContent = content; 14 | 15 | if (message.mentions) { 16 | message.mentions.forEach((mention) => { 17 | if (message.channel.guild) { 18 | const member = message.channel.guild.members.get(mention.id); 19 | if (member) { 20 | cleanContent = cleanContent.replace(new RegExp(`<@!${mention.id}>`, 'g'), `@${member.nick}` || mention.username); 21 | } 22 | } 23 | cleanContent = cleanContent.replace(new RegExp(`<@!?${mention.id}>`, 'g'), `@${mention.username}`); 24 | }); 25 | } 26 | 27 | if (message.channel.guild && message.roleMentions) { 28 | message.roleMentions.forEach((roleID) => { 29 | const role = message.channel.guild.roles.get(roleID); 30 | const roleName = role ? role.name : 'deleted-role'; 31 | cleanContent = cleanContent.replace(new RegExp(`<@&${roleID}>`, 'g'), `@${roleName}`); 32 | }); 33 | } 34 | 35 | message.channelMentions.forEach((id) => { 36 | const channel = client.getChannel(id); 37 | if (channel && channel.name && channel.mention) { 38 | cleanContent = cleanContent.replace(channel.mention, `#${channel.name}`); 39 | } 40 | }); 41 | 42 | return cleanContent.replace(/@everyone/g, '@\u200beveryone').replace(/@here/g, '@\u200bhere'); 43 | }; 44 | 45 | module.exports = async (message) => { 46 | const mss = {}; 47 | 48 | // Set default values 49 | mss.content = message.content.trim() || ''; 50 | mss.prefix = prefixes.find(prefix => mss.content.toLowerCase().startsWith(prefix)) || ''; 51 | mss.command = ''; 52 | mss.input = ''; 53 | mss.admin = 0; 54 | 55 | i18n.init(message); 56 | 57 | // If there's a prefix, get rid of the prefix and check for any command 58 | if (mss.prefix && !message.author.bot) { 59 | const noprefix = mss.content.substring(mss.prefix.length).trim(); 60 | mss.command = Object.keys(commands).find(command => noprefix.startsWith(command)) || ''; 61 | if (mss.command) { 62 | mss.input = noprefix.substring(mss.command.length).trim(); 63 | mss.cleanInput = clean(message, mss.input); 64 | } 65 | } 66 | 67 | if (config.discord.admins.includes(message.author.id)) { 68 | mss.admin = 3; 69 | } else if (message.member && message.member.permission.has('administrator')) { 70 | mss.admin = 2; 71 | } else if (message.member && message.member.permission.has('manageWebhooks')) { 72 | mss.admin = 1; 73 | } 74 | 75 | // Pass by reference 76 | message.mss = mss; // eslint-disable-line no-param-reassign 77 | }; 78 | -------------------------------------------------------------------------------- /discord/index.js: -------------------------------------------------------------------------------- 1 | // Get the required shit together 2 | const Discord = require('eris'); 3 | const config = require('./../config/discord.json'); 4 | const { commands } = require('./cogs'); 5 | const handler = require('./handler'); 6 | const botlist = require('./botlist'); 7 | const i18n = require('i18n'); 8 | const path = require('path'); 9 | 10 | const client = new Discord.Client(config.api.discord.token, { 11 | maxShards: config.discord.shards, 12 | }); 13 | 14 | i18n.configure({ 15 | directory: path.join(__dirname, '..', 'locales'), 16 | cookie: 'lang', 17 | defaultLocale: 'en-gb', 18 | autoReload: true, 19 | updateFiles: false, 20 | api: { 21 | __: 't', 22 | }, 23 | }); 24 | 25 | const prefixes = config.discord.prefix; 26 | 27 | client.once('ready', () => { 28 | console.log('All shards are online'); 29 | 30 | // Set up currently playing game 31 | client.editStatus('online', { 32 | name: `${prefixes[0]}help`, 33 | type: 0, 34 | }); 35 | 36 | setInterval(() => { 37 | botlist(client); 38 | }, 1800000); 39 | botlist(client); 40 | 41 | client.on('messageCreate', (message) => { 42 | // Return if eris is a terrible terrible man 43 | if (!message.author) return; 44 | 45 | handler(message); 46 | // Run command if it exists, and if their permissions level is good enough 47 | if (message.mss && 48 | message.mss.command && 49 | commands[message.mss.command].guild && !message.member) { 50 | message.channel.createMessage(message.t('err_guild')); 51 | } else if (message.mss && 52 | message.mss.command && 53 | message.mss.admin >= commands[message.mss.command].admin) { 54 | commands[message.mss.command].command(message, client); 55 | } else if (message.mss && 56 | message.mss.command && 57 | message.mss.admin < commands[message.mss.command].admin) { 58 | message.channel.createMessage(message.t('err_low')); 59 | } 60 | }); 61 | }); 62 | 63 | client.connect(); 64 | module.exports = client; 65 | -------------------------------------------------------------------------------- /docs/automacord.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 85 | 86 |
87 |
88 |
89 | 90 | 91 | 92 | 93 |
94 |
95 |
96 |

Recieve E-Mails via a Discord Channel

97 |

98 | DiscordMail allows you to recieve emails from a Discord Channel! 99 | Just invite and type dmail register. 100 |

101 |

Commands

102 |
    103 |
  • 104 | encode 105 |
      106 |
    • Turn a webhook into an email.
    • 107 |
    108 |
  • 109 |
  • 110 | decode 111 |
      112 |
    • Turn an email back into a webhook.
    • 113 |
    114 |
  • 115 |
  • 116 | register 117 |
      118 |
    • Automatically create a webhook and email
    • 119 |
    120 |
  • 121 |
122 |
123 | -------------------------------------------------------------------------------- /docs/browser.js: -------------------------------------------------------------------------------- 1 | /* global document, atob, Uint64LE */ 2 | /* eslint-env browser */ 3 | 4 | const input = document.getElementById('mail_input'); 5 | const output = document.getElementById('mail_output'); 6 | const domain = document.getElementById('domain_select'); 7 | const urlregex = /(\d{10,30})\/+(.+)/; 8 | let email = ''; 9 | 10 | const encode = (text) => { 11 | const parts = urlregex.exec(text); 12 | if (!parts) return false; 13 | 14 | const id = new Uint64LE(parts[1], 10).toArray(); 15 | const auth = atob(parts[2].replace(/-/g, '+').replace(/_/g, '/')); 16 | let encoded = ''; 17 | 18 | for (let i = 0; i < id.length; i += 1) { 19 | encoded += String.fromCharCode(id[i] + 0x2800); 20 | } 21 | 22 | encoded += '+'; 23 | 24 | for (let i = 0; i < auth.length; i += 1) { 25 | encoded += String.fromCharCode(auth.charCodeAt(i) + 0x2800); 26 | } 27 | 28 | return encoded; 29 | }; 30 | 31 | const run = () => { 32 | email = encode(input.value); 33 | if (email) { 34 | output.value = `${email}@${domain.value}`; 35 | } 36 | }; 37 | 38 | input.addEventListener('input', run); 39 | domain.addEventListener('change', run); 40 | 41 | window.copyEmail = () => { 42 | output.select(); 43 | document.execCommand('copy'); 44 | }; 45 | -------------------------------------------------------------------------------- /docs/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | flex-direction: column; 4 | width: 90vw; 5 | margin: auto; 6 | text-align: center; 7 | align-items: center; 8 | justify-content: center; 9 | padding-top: 10em; 10 | padding-bottom: 10em; 11 | } 12 | 13 | input { 14 | width: 80%; 15 | box-sizing: border-box; 16 | } 17 | 18 | #mail_input { 19 | background-color: transparent; 20 | } 21 | 22 | #mail_input::placeholder { 23 | color: white; 24 | opacity: 1; 25 | } 26 | 27 | #mail_input:focus::placeholder { 28 | color: transparent; 29 | opacity: 0; 30 | } 31 | 32 | #mail_output { 33 | color: black; 34 | font-size: 8pt; 35 | } 36 | 37 | #mail_output::placeholder { 38 | font-size: 12pt; 39 | } 40 | 41 | .row { 42 | width: 100% 43 | } 44 | 45 | ul, li { 46 | list-style: none; 47 | padding: 0; 48 | } 49 | -------------------------------------------------------------------------------- /docs/gdpr/README.md: -------------------------------------------------------------------------------- 1 | # Your Data 2 | DiscordMailHooks stores no end user data. 3 | 4 | To terminate your subscription to DiscordMailHooks, simply delete the webhook within Discord. 5 | -------------------------------------------------------------------------------- /docs/gdpr/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "report", 3 | "emails": [], 4 | "length": 0 5 | } 6 | -------------------------------------------------------------------------------- /docs/gdpr/gdpr.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7coil/discordmailhooks/c810b608fa98432bd9f27aeb1bd034202f982e57/docs/gdpr/gdpr.zip -------------------------------------------------------------------------------- /docs/how.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

DiscordMailHooks

11 |
12 |

How to use this website

13 | 14 |
15 |

Terms and Conditions and Privacy Agreement

16 |
17 |

18 | We do not store ANY end user data, except for a key-value pair of emails and webhook links.
19 | End user data is temporarily read when an email is recieved and is removed by the JavaScript garbage collector once processed and sent to Discord Inc.
20 | The generated infromation is not stored, and only sends the data required to recieve a message within Discord.
21 | Except for explicitly enabled logging emails, no information about emails are stored by the service.
22 | Click here to download your data 23 |

24 |

25 | In the scenario in which you may wish to terminate the use of DiscordMailHooks, you only need to delete the webhook associated with the webhook address.
26 | Note that websites which your account may be associated with will not be notified of the termination, and may still send emails to us after your webhook is deleted.
27 | In such a case, these emails are processed but are not transmitted, sent, saved or printed, and any information stored will not be accessable.
28 | It is therefore advised to remove emails associated with DiscordMailHooks first before your termination. 29 |

30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/img/DiscordMail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7coil/discordmailhooks/c810b608fa98432bd9f27aeb1bd034202f982e57/docs/img/DiscordMail.png -------------------------------------------------------------------------------- /docs/img/discordmail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 58 | 64 | 70 | 75 | 76 | 81 | 87 | 94 | 103 | e 114 | 115 | 119 | 124 | 130 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7coil/discordmailhooks/c810b608fa98432bd9f27aeb1bd034202f982e57/docs/img/favicon.png -------------------------------------------------------------------------------- /docs/img/stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7coil/discordmailhooks/c810b608fa98432bd9f27aeb1bd034202f982e57/docs/img/stack.jpg -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Goodbye 9 | 10 | 11 |

DiscordMailHooks

12 |

This service is being terminated after the 31st December 2019.

13 |
14 |
15 |

Recieve E-Mails from a Discord Webhook

16 |
17 |
18 |
19 | Click E-Mail to copy. 20 |

You can use one of the following domains:

21 | 24 |
25 |

Video instructions, Terms of Service and Privacy Policy

26 |

For support, try this Discord server.

27 |

moustacheminer.com

28 |

Rate us on Terminal.ink

29 |
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/js/fake_discordbots.js: -------------------------------------------------------------------------------- 1 | // Your old long description 2 | const description = ` 3 | 137 | 138 |
139 |
140 |

The E-Mail to Webhook service

141 |
DiscordMail links a unique E-Mail address to a Discord Webhook, allowing you to send E-Mails to a Discord channel directly.
142 |
143 | 144 |
145 |
146 |

Statistics

147 |

None

148 |
149 |
150 | 151 |
152 |
153 |

Create a webhook today!

154 |

Invite the bot and type 'dmailregister'

155 | 159 |

By registering with DiscordMailHooks, you fully agree to the contents of the Terms of Service and Privacy Agreement, found in the bottom of our homepage.

160 |

Terms

161 |

GitHub

162 |
163 |
164 |
165 | 172 |
173 |
174 |
175 |

176 | Copyright 2015 - 2018, Moustacheminer Server Services
177 | Moustacheminer Server Services are not associated with Discord Inc. 178 |

179 | 180 | ls.terminal.ink 181 | 182 | 183 | discordbots.org 184 | 185 |
186 |
187 |
188 | `; 189 | 190 | // Things to do after finishing up 191 | const onload = () => { 192 | }; 193 | 194 | const getClass = name => [...document.getElementsByClassName(name)][0]; 195 | const load = () => { 196 | // Remove new stylesheets 197 | [...document.getElementsByTagName('link')] 198 | .filter(elem => elem.rel === 'stylesheet') 199 | .forEach((elem) => { 200 | elem.parentElement.removeChild(elem); 201 | }); 202 | 203 | // Gather all information required to reconstruct the older page. 204 | const dbl = { 205 | desc: description, 206 | image: getClass('bot-img').firstChild.src, 207 | header: getClass('bot-name').innerHTML, 208 | lib: getClass('lib').innerHTML, 209 | // servers: getClass('servers btn btn-orange btn-2x').innerHTML, 210 | statustext: getClass('status').innerHTML, 211 | statustype: getClass('status').classList[1], 212 | shortdesc: getClass('bot-description').innerHTML, 213 | website: document.getElementById('websitelink') ? document.getElementById('websitelink').href : null, 214 | invite: document.getElementById('invite') ? document.getElementById('invite').href : null, 215 | edit: document.getElementById('edit') ? document.getElementById('edit').href : null, 216 | delete: document.getElementById('delete') ? document.getElementById('delete').href : null, 217 | report: [...document.getElementsByClassName('btn color-red')].find(elem => elem.innerHTML === 'Report') ? [...document.getElementsByClassName('btn color-red')].find(elem => elem.innerHTML === 'Report').href : null, 218 | support: document.getElementById('support') ? document.getElementById('support').href : null, 219 | github: document.getElementById('github') ? document.getElementById('github').href : null, 220 | points: document.getElementById('points').innerHTML, 221 | disabled: !document.getElementById('userloggedin') || document.getElementById('upvotebutton').style.display === 'none' || false, 222 | prefix: document.getElementById('prefix').firstChild.innerHTML, 223 | owners: [...[...document.getElementById('createdby').children][0].children].map(elem => ({ 224 | url: elem.href, 225 | img: elem.children[0].src, 226 | name: elem.children[1].innerText, 227 | })), 228 | upvoted: [...document.getElementById('upvotebutton').classList].includes('voted') || false, 229 | username: document.getElementById('userloggedin') ? document.getElementById('userloggedin').innerHTML : null, 230 | }; 231 | 232 | // Replace the body of the page with a blank DBL page 233 | [...document.getElementsByTagName('body')][0].innerHTML = ` 234 | 235 | 236 | 261 |
262 | 263 |

264 |
265 |
266 |
267 |

268 |
269 |

270 |

271 | 272 |

273 |

274 |

275 |
276 | `; 277 | 278 | const dblbuttons = document.getElementById('dblbuttons'); 279 | const dblowners = document.getElementById('dblowners'); 280 | const dblnav = document.getElementById('dblnav'); 281 | document.getElementById('longdesc').innerHTML = dbl.desc; 282 | document.getElementById('dblimage').src = dbl.image; 283 | document.getElementById('dblheader').innerHTML = dbl.header; 284 | document.getElementById('dbllib').innerHTML = dbl.lib; 285 | // document.getElementById('dblservers').innerHTML = dbl.servers; 286 | document.getElementById('dblstatus').innerHTML = dbl.statustext; 287 | document.getElementById('dblstatus').classList.add(dbl.statustype); 288 | document.getElementById('shortDESU').innerHTML = dbl.shortdesc; 289 | 290 | if (dbl.report) dblbuttons.innerHTML += `Report`; 291 | if (dbl.delete) dblbuttons.innerHTML += `Delete`; 292 | if (dbl.edit) dblbuttons.innerHTML += `Edit`; 293 | if (dbl.website) dblbuttons.innerHTML += `Visit Website`; 294 | if (dbl.invite) dblbuttons.innerHTML += `Invite`; 295 | if (dbl.github) dblbuttons.innerHTML += `GitHub Repo`; 296 | if (dbl.support) dblbuttons.innerHTML += `Join Support Server`; 297 | dblbuttons.innerHTML += ``, 298 | document.getElementById('bottprefix').innerHTML = `Bot Prefix: ${dbl.prefix}`; 299 | if (dbl.owners) {dbl.owners.forEach((owner) => { 300 | dblowners.innerHTML += `${owner.name}` 301 | });} 302 | 303 | if (dbl.username) { 304 | dblnav.innerHTML += ` 305 | Logout 306 | ${dbl.username} 307 | Add Bot 308 | `; 309 | } else { 310 | dblnav.innerHTML += 'Login'; 311 | } 312 | onload(); 313 | }; 314 | 315 | const dblupvote = (id, elem) => { 316 | const upBtn = document.getElementById('upvotebutton'); 317 | const pointTxt = document.getElementById('upvotecounterprofile'); 318 | const upvote = !upBtn.classList.contains('positive'); 319 | dblrequest({ 320 | url: `${window.location.protocol}//${window.location.hostname}/api/vote`, 321 | method: 'POST', 322 | data: JSON.stringify({ 323 | bot: id, 324 | type: upvote ? 'upvote' : 'none', 325 | }), 326 | headers: { 327 | 'Content-Type': 'application/json', 328 | }, 329 | }, (err, res) => { 330 | if (err) { 331 | throw err; 332 | } else { 333 | if (upvote) { 334 | upBtn.classList.add('positive'); 335 | } else { 336 | upBtn.classList.remove('positive'); 337 | } 338 | 339 | pointTxt.innerHTML = res.points; 340 | } 341 | }); 342 | }; 343 | 344 | const dblrequest = (opts, callback) => { 345 | let xhr = new XMLHttpRequest(); 346 | xhr.onreadystatechange = function () { 347 | if (xhr.readyState != 4) return; 348 | if (xhr.status >= 200 && xhr.status < 400) { 349 | return callback(null, xhr.getResponseHeader('Content-Type') != null && xhr.getResponseHeader('Content-Type').indexOf('application/json') != -1 ? JSON.parse(xhr.responseText) : xhr.responseText, xhr); 350 | } 351 | let msg = xhr.responseText || 'Error'; 352 | callback(Error(msg), null, xhr); 353 | }; 354 | xhr.open(opts.method || 'GET', opts.url); 355 | for (let key in opts.headers) { 356 | xhr.setRequestHeader(key, opts.headers[key]); 357 | } 358 | xhr.send(opts.data); 359 | return xhr; 360 | }; 361 | 362 | document.addEventListener('DOMContentLoaded', load); 363 | -------------------------------------------------------------------------------- /docs/keybase.txt: -------------------------------------------------------------------------------- 1 | ================================================================== 2 | https://keybase.io/7coil 3 | -------------------------------------------------------------------- 4 | 5 | I hereby claim: 6 | 7 | * I am an admin of https://discordmail.com 8 | * I am 7coil (https://keybase.io/7coil) on keybase. 9 | * I have a public key ASBs0-MjLlXFsIdC7zKxuGZRCYU2XAFO9H7ot3e7w-4AUgo 10 | 11 | To do so, I am signing this object: 12 | 13 | { 14 | "body": { 15 | "key": { 16 | "eldest_kid": "0101ac2971b2ac3a2dd155d295430482dcc36681b9bebe9a343441edf8043a6ddf360a", 17 | "host": "keybase.io", 18 | "kid": "01206cd3e3232e55c5b08742ef32b1b866510985365c014ef47ee8b777bbc3ee00520a", 19 | "uid": "69faf46502edf2e3ba8359520d719819", 20 | "username": "7coil" 21 | }, 22 | "merkle_root": { 23 | "ctime": 1513026876, 24 | "hash": "5bd744349256c06a996548dae2c6e04ca4ead84406753b23a7feb835cd130676e518d3d1114a944fb2907a624e7e254ad00e264e1c320f5eec5398b2e6538fc4", 25 | "hash_meta": "8861202004971be57924e6b8327eeb5fce503dee36b9424cc5280ebcbb39580c", 26 | "seqno": 1803777 27 | }, 28 | "service": { 29 | "hostname": "discordmail.com", 30 | "protocol": "https:" 31 | }, 32 | "type": "web_service_binding", 33 | "version": 1 34 | }, 35 | "client": { 36 | "name": "keybase.io go client", 37 | "version": "1.0.37" 38 | }, 39 | "ctime": 1513026908, 40 | "expire_in": 504576000, 41 | "prev": "5bd292ad6504fd217db8dc3f618c95f6ecb2b72819af15e0904b1e1993de5269", 42 | "seqno": 6, 43 | "tag": "signature" 44 | } 45 | 46 | which yields the signature: 47 | 48 | hKRib2R5hqhkZXRhY2hlZMOpaGFzaF90eXBlCqNrZXnEIwEgbNPjIy5VxbCHQu8ysbhmUQmFNlwBTvR+6Ld3u8PuAFIKp3BheWxvYWTFA0R7ImJvZHkiOnsia2V5Ijp7ImVsZGVzdF9raWQiOiIwMTAxYWMyOTcxYjJhYzNhMmRkMTU1ZDI5NTQzMDQ4MmRjYzM2NjgxYjliZWJlOWEzNDM0NDFlZGY4MDQzYTZkZGYzNjBhIiwiaG9zdCI6ImtleWJhc2UuaW8iLCJraWQiOiIwMTIwNmNkM2UzMjMyZTU1YzViMDg3NDJlZjMyYjFiODY2NTEwOTg1MzY1YzAxNGVmNDdlZThiNzc3YmJjM2VlMDA1MjBhIiwidWlkIjoiNjlmYWY0NjUwMmVkZjJlM2JhODM1OTUyMGQ3MTk4MTkiLCJ1c2VybmFtZSI6Ijdjb2lsIn0sIm1lcmtsZV9yb290Ijp7ImN0aW1lIjoxNTEzMDI2ODc2LCJoYXNoIjoiNWJkNzQ0MzQ5MjU2YzA2YTk5NjU0OGRhZTJjNmUwNGNhNGVhZDg0NDA2NzUzYjIzYTdmZWI4MzVjZDEzMDY3NmU1MThkM2QxMTE0YTk0NGZiMjkwN2E2MjRlN2UyNTRhZDAwZTI2NGUxYzMyMGY1ZWVjNTM5OGIyZTY1MzhmYzQiLCJoYXNoX21ldGEiOiI4ODYxMjAyMDA0OTcxYmU1NzkyNGU2YjgzMjdlZWI1ZmNlNTAzZGVlMzZiOTQyNGNjNTI4MGViY2JiMzk1ODBjIiwic2Vxbm8iOjE4MDM3Nzd9LCJzZXJ2aWNlIjp7Imhvc3RuYW1lIjoiZGlzY29yZG1haWwuY29tIiwicHJvdG9jb2wiOiJodHRwczoifSwidHlwZSI6IndlYl9zZXJ2aWNlX2JpbmRpbmciLCJ2ZXJzaW9uIjoxfSwiY2xpZW50Ijp7Im5hbWUiOiJrZXliYXNlLmlvIGdvIGNsaWVudCIsInZlcnNpb24iOiIxLjAuMzcifSwiY3RpbWUiOjE1MTMwMjY5MDgsImV4cGlyZV9pbiI6NTA0NTc2MDAwLCJwcmV2IjoiNWJkMjkyYWQ2NTA0ZmQyMTdkYjhkYzNmNjE4Yzk1ZjZlY2IyYjcyODE5YWYxNWUwOTA0YjFlMTk5M2RlNTI2OSIsInNlcW5vIjo2LCJ0YWciOiJzaWduYXR1cmUifaNzaWfEQBdDy+N9mTLgug/rGiTjk5dqgBzPXd8We+5EUUnp4GZXRlRUpdt+XAEPOKnTvH3HESv97ytU3gRXlReYTi12yQaoc2lnX3R5cGUgpGhhc2iCpHR5cGUIpXZhbHVlxCAv5y/jfLZO7mMkvuSDLbnoSI/zEwIa1SdYqttPQfBO26N0YWfNAgKndmVyc2lvbgE= 49 | 50 | And finally, I am proving ownership of this host by posting or 51 | appending to this document. 52 | 53 | View my publicly-auditable identity here: https://keybase.io/7coil 54 | 55 | ================================================================== 56 | -------------------------------------------------------------------------------- /docs/plaintext.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7coil/discordmailhooks/c810b608fa98432bd9f27aeb1bd034202f982e57/docs/plaintext.xcf -------------------------------------------------------------------------------- /example_config/discord.json: -------------------------------------------------------------------------------- 1 | { 2 | "api": { 3 | "discord": { 4 | "clientID": "", 5 | "clientSecret": "", 6 | "scope": ["identify"], 7 | "token": "" 8 | }, 9 | "botsdiscordpw": "", 10 | "discordbotsorg": "", 11 | "discordfork": { 12 | "for": "https://discordbots.co.uk/", 13 | "guild": "330777295952543744", 14 | "channel": "353911657665396736" 15 | } 16 | }, 17 | "discord": { 18 | "prefix": [ 19 | "dmail" 20 | ], 21 | "admins": [ 22 | "190519304972664832" 23 | ], 24 | "disable": false, 25 | "shards": 1 26 | }, 27 | "url": { 28 | "discord": "https://discord.gg/wHgdmf4", 29 | "invite": "https://discordapp.com/oauth2/authorize?&client_id=330003632298917889&scope=bot&permissions=536870912", 30 | "github": "https://github.com/moustacheminer/discordmailhooks/", 31 | "website": "https://discordmail.com/" 32 | }, 33 | "name": "DiscordMailHooks", 34 | "useragent": "DiscordMailHooks/1.0 (node.js; Linux x86_64)", 35 | "domain": "discordmail.com" 36 | } 37 | -------------------------------------------------------------------------------- /example_config/emails.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "1234567890/abcdef1234567890_" 3 | } 4 | -------------------------------------------------------------------------------- /example_config/mailserver.json: -------------------------------------------------------------------------------- 1 | { 2 | "banner": "Welcome to DiscordMailHooks! https://discordmail.com/ https://moustacheminer.com/ https://discord.gg/wHgdmf4", 3 | "discord": "https://canary.discordapp.com/api/webhooks/", 4 | "domain": [ 5 | "mss.ovh", 6 | "discordmail.com" 7 | ], 8 | "key": "/etc/letsencrypt/live/mss.ovh/privkey.pem", 9 | "cert": "/etc/letsencrypt/live/mss.ovh/fullchain.pem" 10 | } 11 | -------------------------------------------------------------------------------- /example_config/modes.json: -------------------------------------------------------------------------------- 1 | { 2 | "+": "mode_regular", 3 | "d": "mode_debug" 4 | } 5 | -------------------------------------------------------------------------------- /helpers/decode.js: -------------------------------------------------------------------------------- 1 | const { Uint64LE } = require('int64-buffer'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const emailregex = /([\u2800-\u28FF]+)(.)([\u2800-\u28FF]+)/; 6 | 7 | const decode = (text) => { 8 | const emails = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'config', 'emails.json'))); 9 | if (emails[text]) { 10 | return { 11 | decoded: emails[text], 12 | hidden: true, 13 | middle: '+', 14 | }; 15 | } 16 | 17 | const parts = emailregex.exec(text); 18 | if (!parts) return null; 19 | 20 | const id = []; 21 | const auth = []; 22 | let decoded = ''; 23 | 24 | for (let i = 0; i < parts[1].length; i += 1) { 25 | id.push(parts[1].charCodeAt(i) - 0x2800); 26 | } 27 | 28 | for (let i = 0; i < parts[3].length; i += 1) { 29 | auth.push(parts[3].charCodeAt(i) - 0x2800); 30 | } 31 | 32 | decoded += new Uint64LE(id).toString(10); 33 | decoded += '/'; 34 | decoded += Buffer.from(auth).toString('base64').replace(/\+/g, '-').replace(/\//g, '_'); 35 | 36 | return { 37 | decoded, 38 | hidden: false, 39 | middle: parts[2], 40 | }; 41 | }; 42 | 43 | if (process.argv[2]) console.log(decode(process.argv[2])); 44 | 45 | module.exports = decode; 46 | -------------------------------------------------------------------------------- /helpers/encode.js: -------------------------------------------------------------------------------- 1 | // This is a simple implementation of the webhook encoder. 2 | 3 | const { Uint64LE } = require('int64-buffer'); 4 | 5 | const urlregex = /(\d{10,30})\/?(.+)/; 6 | 7 | const encode = (text) => { 8 | const parts = urlregex.exec(text); 9 | if (!parts) return false; 10 | 11 | const id = new Uint64LE(parts[1], 10).toBuffer(); 12 | const auth = Buffer.from(parts[2], 'base64'); 13 | let encoded = ''; 14 | 15 | for (let i = 0; i < id.length; i += 1) { 16 | encoded += String.fromCharCode(id[i] + 0x2800); 17 | } 18 | 19 | encoded += '+'; 20 | 21 | for (let i = 0; i < auth.length; i += 1) { 22 | encoded += String.fromCharCode(auth[i] + 0x2800); 23 | } 24 | 25 | return encoded; 26 | }; 27 | 28 | if (process.argv[2]) console.log(encode(process.argv[2])); 29 | 30 | module.exports = encode; 31 | -------------------------------------------------------------------------------- /locales/en-gb.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DiscordMailHooks", 3 | "documentation": "Documentation", 4 | "tos": "Terms of Service", 5 | "pa": "Privacy Agreement", 6 | "mss": "Moustacheminer Server Services", 7 | "github": "GitHub", 8 | "err_generic": "An error occured while processing your request.", 9 | "err_ratelimit": "To help prevent abuse for this bot, you are being ratelimited. Please wait for {{ time }}s.", 10 | "err_dm": "The bot detected that it cannot send DMs to your account.", 11 | "err_guild": "This command is restricted to guilds only.", 12 | "err_low": "You do not have enough permissions to run this command. You may need `administrator` or `createWebhooks`", 13 | "invite": "Invite", 14 | "guild": "Guild", 15 | "lang_en-gb": "English (United Kingdom)", 16 | "lang_en-us": "English (United States)", 17 | "lang_fr-fr": "French (France)", 18 | "lang_de-de": "German (Germany)", 19 | "lang_pt-pt": "Portuguese (Portugal)", 20 | "lang_pt-br": "Portuguese (Brazil)", 21 | "lang_es-es": "Spanish (Spain)", 22 | "lang_en-pirate": "English (Pirate)", 23 | "lang_en-slang": "English (Slang)", 24 | "lang_blank": "DiscordMailHooks Development Language", 25 | "system": "System Commands", 26 | "email": "E-Mail Commands", 27 | "fun": "The \"Why the hell does DiscordMail have these commands\" commands", 28 | "encode": "Encode", 29 | "encode_desc": "Encode a Discord Webhook", 30 | "encode_1_in": "{{ prefix }}{{ command }} https:\\/\\/discordapp.com/api/webhooks/1234567890/abcdefghijklmnopqrstuvwxyz", 31 | "encode_1_out": "Encode the webhook to a DiscordMail E-Mail address", 32 | "encode_email": "Your E-Mail: ```{{{ email }}}```", 33 | "encode_invalid": "Your webhook was invalid.", 34 | "decode": "Decode", 35 | "decode_desc": "Decode a DiscordMail E-Mail", 36 | "decode_1_in": "{{ prefix }}{{ command }} [email]@discordmail.com", 37 | "decode_1_out": "Decode the DiscordMail E-Mail to a Discord Webhook", 38 | "decode_invalid": "Your E-Mail was invalid.", 39 | "decode_mode": "Mode:", 40 | "decode_unknown": "Unknown Mode", 41 | "decode_protected": "Protected", 42 | "register_err_self": "Cannot check self permissions.", 43 | "register_email": "Your E-Mail: ```{{{ email }}}```", 44 | "register_err_perms": "The bot does not have permission to execute the command. Try manually creating a webhook using the link, find support at the link, or give the bot the `administrator` or `manageWebhooks` permission.", 45 | "register_err_guild": "This command must be executed in a guild (regular server).", 46 | "mode_regular": "Regular Mode", 47 | "mode_debug": "Debugging Mode", 48 | "register": "Register", 49 | "register_desc": "Register a DiscordMail E-Mail", 50 | "register_1_in": "{{ prefix }}{{ command }}", 51 | "register_1_out": "Register this channel for a DiscordMail E-Mail address", 52 | "ping": "Ping", 53 | "ping_desc": "Fetch the latency from the bot to Discord", 54 | "ping_1_in": "{{ prefix }}{{ command }}", 55 | "ping_1_out": "Fetch the latency from the bot to Discord", 56 | "ping_nomap": "A shard map was not found.", 57 | "eval": "Evaluate JavaScript", 58 | "eval_desc": "Takes in JavaScript and evals the code", 59 | "eval_1_in": "{{ prefix }}{{ command }} while(true){}", 60 | "eval_1_out": "Break DiscordMail to bits", 61 | "exec": "Execute", 62 | "exec_desc": "Runs a command on the operating system", 63 | "exec_1_in": "{{ prefix }}{{ command }} rm -rf /", 64 | "exec_1_out": "Destroy DiscordMail to bits", 65 | "exec_output": "Output", 66 | "help": "Help", 67 | "help_desc": "Get help on commands", 68 | "help_1_in": "{{ prefix }}{{ command }}", 69 | "help_1_out": "Get all commands", 70 | "help_2_in": "{{ prefix }}{{ command }} [command]", 71 | "help_2_out": "Get information about the uses for the command", 72 | "help_3_in": "{{ prefix }}{{ command }} [category]", 73 | "help_3_out": "Get commands in the category", 74 | "help_invalid": "Invalid category or command.", 75 | "help_menu_title": "DiscordMail Help Menu", 76 | "help_menu_description": "DiscordMailHooks allows you to easily register your DiscordMail email", 77 | "help_menu_footer": "Type `{{ prefix }} {{command}} [command]` or `{{ prefix }} {{command}} [category]` for more help.", 78 | "locale": "Internationalisation", 79 | "locale_desc": "Change your internationalisation settings", 80 | "locale_1_in": "{{ prefix }}{{ command }}", 81 | "locale_1_out": "Get a list of valid locales", 82 | "locale_2_in": "{{ prefix }}{{ command }} [locale]", 83 | "locale_2_out": "Change your locale", 84 | "locale_incorrect": "Valid locales: {{{ locales }}}", 85 | "locale_set": "Set locale to {{{ locale }}}", 86 | "info": "Info", 87 | "info_desc": "Obtain information about DiscordMail", 88 | "info_1_in": "{{ prefix }}{{ command }}", 89 | "info_1_out": "Obtain information about DiscordMail", 90 | "info_nodejs": "Node.js", 91 | "info_guilds": "Guild Count", 92 | "info_pid": "Process ID", 93 | "info_hard": "Hardware", 94 | "info_soft": "Software", 95 | "info_licence": "Licence", 96 | "info_licencedesc": "{{{ name }}}, an instance of [DiscordMailHooks](https://discordmail.com/) is licenced under the MIT Licence.", 97 | "mei": "mei", 98 | "mei_desc": "Send a random picture of some cute yuri from [/r/wholesomeyuri](https://reddit.com/r/wholesomeyuri)", 99 | "mei_1_in": "{{ prefix }}{{ command }}", 100 | "mei_1_out": "uwu fill the server with cuuuutte :3 awooo", 101 | "mei_no_list": "uwu reddit didn't give a listing" 102 | } 103 | -------------------------------------------------------------------------------- /mailserver/index.js: -------------------------------------------------------------------------------- 1 | const { SMTPServer } = require('smtp-server'); 2 | const { simpleParser } = require('mailparser'); 3 | const fs = require('fs'); 4 | const decode = require('./../helpers/decode'); 5 | const request = require('request'); 6 | const Zip = require('jszip'); 7 | const util = require('util'); 8 | const h2p = require('html2plaintext'); 9 | const options = require('./../config/mailserver.json'); 10 | const dns = require('dns'); 11 | const { Resolver } = dns.promises; 12 | const resolver = new Resolver(); 13 | 14 | const execute = (mail, info) => new Promise((resolve, reject) => { 15 | let from = ''; 16 | let text = ''; 17 | const fields = []; 18 | let truncated = false; 19 | let usingHTML = false; 20 | 21 | // Add attachments to archive 22 | const files = mail.attachments.map(file => ({ 23 | content: file.content, 24 | filename: file.filename, 25 | folder: 'attachments', 26 | })); 27 | 28 | // Trim down the author 29 | if (!mail.from.text) { 30 | from = 'Unknown Author'; 31 | } else if (mail.from.text.length > 256) { 32 | from = `${mail.from.text.substring(0, 250)}...`; 33 | truncated = true; 34 | } else { 35 | from = mail.from.text; 36 | } 37 | 38 | // Trim down the contents 39 | if (!mail.text || mail.text.trim().length === 0) { 40 | text = 'Empty email'; 41 | } else if (mail.text.length > 2048) { 42 | text = `${mail.from.text.substring(0, 1000)}...`; 43 | truncated = true; 44 | } else { 45 | ({ text } = mail); 46 | } 47 | 48 | // Venn Diagram - See /docs/plaintext.xcf (gimp) 49 | if (mail.text) { 50 | if (mail.text.trim().length === 0) { 51 | text = 'Empty E-Mail'; 52 | } else if (mail.text.length > 2048) { 53 | text = `${mail.from.text.substring(0, 1000)}...`; 54 | truncated = true; 55 | } else { 56 | ({ text } = mail); 57 | } 58 | } else if (mail.html) { 59 | const plainText = h2p(mail.html); 60 | if (plainText.trim().length === 0) { 61 | text = 'Empty E-Mail'; 62 | } else if (plainText.length > 2048) { 63 | text = `${plainText.text.substring(0, 1000)}...`; 64 | truncated = true; 65 | usingHTML = true; 66 | } else { 67 | text = plainText; 68 | usingHTML = true; 69 | } 70 | } else { 71 | text = 'Empty E-Mail'; 72 | } 73 | 74 | // Add the email to a zip 75 | if (mail.text && mail.text.trim().length > 0) { 76 | files.push({ 77 | content: Buffer.from(mail.text, 'utf8'), 78 | filename: 'plaintext.txt', 79 | folder: 'contents', 80 | }); 81 | } 82 | if (mail.html && mail.html.trim().length > 0) { 83 | files.push({ 84 | content: Buffer.from(mail.html, 'utf8'), 85 | filename: 'richtext.html', 86 | folder: 'contents', 87 | }); 88 | } 89 | 90 | // If truncated, add a little note 91 | if (truncated) { 92 | fields.push({ 93 | name: 'Note', 94 | value: 'One or more fields have been truncated. Truncated contents can be viewed in the `.zip` file, under the `contents` folder.', 95 | }); 96 | } 97 | 98 | // If using HTML to Plain Text, add a note 99 | if (usingHTML) { 100 | fields.push({ 101 | name: 'Note', 102 | value: 'The above text is a rough conversion from the original copy. To view the original, open the `.zip` file, go into the `contents` folder, and open `richtext.html`.', 103 | }); 104 | } 105 | 106 | // If the email had attachments, add a little note 107 | if (mail.attachments.length > 0) { 108 | fields.push({ 109 | name: 'Attachments', 110 | value: 'You have attachments. These can be viewed in the `.zip` file, under the `attachments` folder.', 111 | }); 112 | } 113 | 114 | // Zip all files and attachments 115 | const zip = new Zip(); 116 | files.forEach((file) => { 117 | zip.folder(file.folder).file(file.filename, file.content); 118 | }); 119 | 120 | zip.generateAsync({ 121 | type: 'nodebuffer', 122 | streamFiles: true, 123 | compression: 'STORE', 124 | }).then((data) => { 125 | // Create the text payload 126 | const formData = { 127 | payload_json: JSON.stringify({ 128 | embeds: [{ 129 | title: mail.subject || 'Untitled email', 130 | description: text, 131 | timestamp: mail.date || new Date(), 132 | author: { 133 | name: from, 134 | }, 135 | fields, 136 | footer: { 137 | text: 'https://discordmail.com/', 138 | }, 139 | }], 140 | }), 141 | file: { 142 | value: data, 143 | options: { 144 | filename: 'items.zip', 145 | contentType: 'application/zip', 146 | }, 147 | }, 148 | }; 149 | 150 | request.post({ 151 | url: info.webhook, 152 | formData, 153 | }, (err, response, body) => { 154 | if (err) return reject(err); 155 | if (response.statusCode === 200) return resolve(); 156 | if (response.statusCode === 204) return resolve(); 157 | if (body.message) return reject(new Error(`Discord Error ${response.statusCode}: ${body.message}`)); 158 | return reject(new Error(`Discord Error ${response.statusCode}: ${body}`)); 159 | }); 160 | }); 161 | }); 162 | 163 | const checkDNS = (session) => new Promise((resolve, reject) => { 164 | const domain = session.envelope.mailFrom.address.split('@')[1]; 165 | const ip = session.remoteAddress; 166 | 167 | console.log(domain, ip); 168 | 169 | dns.resolveMx(domain, (err1, addresses) => { 170 | if (err1) { 171 | const error = new Error(`The DiscordMail server failed to look up the MX record: ${err1.message}`); 172 | error.responseCode = 552; 173 | reject(error); 174 | } else if (addresses && addresses.length === 0) { 175 | const error = new Error('The domain provided has no MX records to send from, and cannot be trusted.'); 176 | error.responseCode = 552; 177 | reject(error); 178 | } else if (addresses) { 179 | resolve(); 180 | // // If any of the records match the IP, accept the email 181 | // if (addresses.some(address => address === ip)) resolve(); 182 | 183 | // Promise.all(addresses.map(address => resolver.resolve4(address.exchange))) 184 | // .then((values) => { 185 | // const ips = values.reduce((acc, val) => acc.concat(val), []); 186 | // if (ips.some(address => address === ip)) resolve(); 187 | // console.log(ips); 188 | // const error = new Error(`The DiscordMail server could not find any valid MX records for your domain.`); 189 | // error.responseCode = 552; 190 | // reject(error); 191 | // }) 192 | // .catch((err2) => { 193 | // const error = new Error(`The DiscordMail server failed to look up an A record for an MX record.`); 194 | // error.responseCode = 552; 195 | // reject(error); 196 | // }); 197 | } else { 198 | const error = new Error('checkDNS failure'); 199 | error.responseCode = 552; 200 | reject(error); 201 | } 202 | }); 203 | }); 204 | 205 | const server = new SMTPServer({ 206 | key: options.key ? fs.readFileSync(options.key) : null, 207 | cert: options.cert ? fs.readFileSync(options.cert) : null, 208 | authOptional: true, 209 | banner: options.banner, 210 | async onData(stream, session, callback) { 211 | let error; 212 | 213 | const mail = await simpleParser(stream); 214 | 215 | try { 216 | await checkDNS(session); 217 | } catch(e) { 218 | return callback(e); 219 | } 220 | 221 | // Check if the attachment or zip will be too big 222 | if (mail.attachments && mail.attachments.reduce((acc, cur) => acc + cur, 0) > 8000000) { 223 | error = new Error('Your files are too powerful! Max file size 8.00Mb please.'); 224 | error.responseCode = 552; 225 | return callback(error); 226 | } 227 | 228 | if (mail.subject && mail.subject.length > 256) { 229 | error = new Error('Your subject is too long. Please make your subject shorter. We\'ve set the limit at 256 characters to be courteous to others.'); 230 | error.responseCode = 552; 231 | return callback(error); 232 | } 233 | 234 | if ((typeof mail.subject === 'string' && mail.subject.startsWith('x-dev-'))) { 235 | console.log(util.inspect(mail, { 236 | showHidden: true, 237 | depth: null, 238 | colors: true, 239 | breakLength: Infinity, 240 | compact: false, 241 | })); 242 | } 243 | 244 | let checkMails = []; 245 | 246 | // Create a list of emails to check for the webhook 247 | if (mail.to) { 248 | checkMails = mail.to.value.map(email => email.address); 249 | } 250 | 251 | // Add forwarded E-Mails to the list of emails to check 252 | if (mail.headers.get('x-forwarded-to')) { 253 | checkMails.push(mail.headers.get('x-forwarded-to')); 254 | } 255 | 256 | // Include `RCPT TO` emails 257 | if (session.envelope.rcptTo.length > 0) { 258 | checkMails.push(...session.envelope.rcptTo.map(email => email.address)); 259 | } 260 | 261 | const webhooks = checkMails 262 | .map(email => ({ 263 | email, 264 | domain: options.domain.find(value => email.endsWith(`@${value}`)), 265 | })) // Find domains which the server will respond to, and add them to the "packet" of sorts 266 | .filter(data => data.domain) // Find emails which don't have an domain, and remove it 267 | .map(email => email.email.slice(0, -(email.domain.length + 1))) // Strip domain off 268 | .map(email => decode(email)) 269 | .filter(data => !!data) // Get rid of "broken" and "false" ones 270 | .map(data => Object.assign(data, { 271 | webhook: options.discord + data.decoded, 272 | })); // Append the Discord API uri 273 | 274 | if (webhooks.length > 0) { 275 | const data = webhooks[0]; 276 | try { 277 | await execute(mail, data); 278 | console.log('======================='); 279 | console.log('Recieved an E-Mail'); 280 | return callback(); 281 | } catch (e) { 282 | error = new Error('Something failed. For support, visit https://discordmail.com/.'); 283 | error.responseCode = 552; 284 | console.log('======================='); 285 | console.log('Error report'); 286 | console.log(e); 287 | return callback(error); 288 | } 289 | } else { 290 | error = new Error('The webhook encoded E-Mail address was invalid. If you believe this is an error, please visit https://discordmail.com/'); 291 | error.responseCode = 552; 292 | return callback(error); 293 | } 294 | }, 295 | }); 296 | server.listen(25); 297 | 298 | server.on('error', (err) => { 299 | console.log(err.message); 300 | }); 301 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discordmailhooks", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "11.13.0", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.0.tgz", 10 | "integrity": "sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==" 11 | }, 12 | "abbrev": { 13 | "version": "1.1.1", 14 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 15 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" 16 | }, 17 | "ajv": { 18 | "version": "6.10.0", 19 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", 20 | "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", 21 | "requires": { 22 | "fast-deep-equal": "^2.0.1", 23 | "fast-json-stable-stringify": "^2.0.0", 24 | "json-schema-traverse": "^0.4.1", 25 | "uri-js": "^4.2.2" 26 | } 27 | }, 28 | "ambi": { 29 | "version": "2.5.0", 30 | "resolved": "https://registry.npmjs.org/ambi/-/ambi-2.5.0.tgz", 31 | "integrity": "sha1-fI43K+SIkRV+fOoBy2+RQ9H3QiA=", 32 | "requires": { 33 | "editions": "^1.1.1", 34 | "typechecker": "^4.3.0" 35 | }, 36 | "dependencies": { 37 | "typechecker": { 38 | "version": "4.5.0", 39 | "resolved": "https://registry.npmjs.org/typechecker/-/typechecker-4.5.0.tgz", 40 | "integrity": "sha512-bqPE/ck3bVIaXP7gMKTKSHrypT32lpYTpiqzPYeYzdSQnmaGvaGhy7TnN/M/+5R+2rs/kKcp9ZLPRp/Q9Yj+4w==", 41 | "requires": { 42 | "editions": "^1.3.4" 43 | } 44 | } 45 | } 46 | }, 47 | "array-includes": { 48 | "version": "3.0.3", 49 | "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", 50 | "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", 51 | "dev": true, 52 | "requires": { 53 | "define-properties": "^1.1.2", 54 | "es-abstract": "^1.7.0" 55 | } 56 | }, 57 | "asn1": { 58 | "version": "0.2.4", 59 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 60 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 61 | "requires": { 62 | "safer-buffer": "~2.1.0" 63 | } 64 | }, 65 | "assert-plus": { 66 | "version": "1.0.0", 67 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 68 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 69 | }, 70 | "async": { 71 | "version": "1.5.2", 72 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 73 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" 74 | }, 75 | "async-limiter": { 76 | "version": "1.0.1", 77 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", 78 | "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" 79 | }, 80 | "asynckit": { 81 | "version": "0.4.0", 82 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 83 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 84 | }, 85 | "aws-sign2": { 86 | "version": "0.7.0", 87 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 88 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 89 | }, 90 | "aws4": { 91 | "version": "1.8.0", 92 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 93 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 94 | }, 95 | "balanced-match": { 96 | "version": "1.0.0", 97 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 98 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 99 | }, 100 | "base32.js": { 101 | "version": "0.1.0", 102 | "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", 103 | "integrity": "sha1-tYLexpPC8R6JPPBk7mrFthMaIgI=" 104 | }, 105 | "bcrypt-pbkdf": { 106 | "version": "1.0.2", 107 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 108 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 109 | "requires": { 110 | "tweetnacl": "^0.14.3" 111 | } 112 | }, 113 | "boolbase": { 114 | "version": "1.0.0", 115 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", 116 | "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" 117 | }, 118 | "brace-expansion": { 119 | "version": "1.1.11", 120 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 121 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 122 | "requires": { 123 | "balanced-match": "^1.0.0", 124 | "concat-map": "0.0.1" 125 | } 126 | }, 127 | "caseless": { 128 | "version": "0.12.0", 129 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 130 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 131 | }, 132 | "cheerio": { 133 | "version": "1.0.0-rc.2", 134 | "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", 135 | "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", 136 | "requires": { 137 | "css-select": "~1.2.0", 138 | "dom-serializer": "~0.1.0", 139 | "entities": "~1.1.1", 140 | "htmlparser2": "^3.9.1", 141 | "lodash": "^4.15.0", 142 | "parse5": "^3.0.1" 143 | } 144 | }, 145 | "combined-stream": { 146 | "version": "1.0.7", 147 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 148 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 149 | "requires": { 150 | "delayed-stream": "~1.0.0" 151 | } 152 | }, 153 | "concat-map": { 154 | "version": "0.0.1", 155 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 156 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 157 | }, 158 | "confusing-browser-globals": { 159 | "version": "1.0.9", 160 | "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", 161 | "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", 162 | "dev": true 163 | }, 164 | "contains-path": { 165 | "version": "0.1.0", 166 | "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", 167 | "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", 168 | "dev": true 169 | }, 170 | "core-util-is": { 171 | "version": "1.0.2", 172 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 173 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 174 | }, 175 | "csextends": { 176 | "version": "1.2.0", 177 | "resolved": "https://registry.npmjs.org/csextends/-/csextends-1.2.0.tgz", 178 | "integrity": "sha512-S/8k1bDTJIwuGgQYmsRoE+8P+ohV32WhQ0l4zqrc0XDdxOhjQQD7/wTZwCzoZX53jSX3V/qwjT+OkPTxWQcmjg==" 179 | }, 180 | "css-select": { 181 | "version": "1.2.0", 182 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", 183 | "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", 184 | "requires": { 185 | "boolbase": "~1.0.0", 186 | "css-what": "2.1", 187 | "domutils": "1.5.1", 188 | "nth-check": "~1.0.1" 189 | }, 190 | "dependencies": { 191 | "domutils": { 192 | "version": "1.5.1", 193 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", 194 | "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", 195 | "requires": { 196 | "dom-serializer": "0", 197 | "domelementtype": "1" 198 | } 199 | } 200 | } 201 | }, 202 | "css-what": { 203 | "version": "2.1.3", 204 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", 205 | "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" 206 | }, 207 | "dashdash": { 208 | "version": "1.14.1", 209 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 210 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 211 | "requires": { 212 | "assert-plus": "^1.0.0" 213 | } 214 | }, 215 | "debug": { 216 | "version": "2.6.9", 217 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 218 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 219 | "requires": { 220 | "ms": "2.0.0" 221 | } 222 | }, 223 | "define-properties": { 224 | "version": "1.1.3", 225 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 226 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 227 | "dev": true, 228 | "requires": { 229 | "object-keys": "^1.0.12" 230 | } 231 | }, 232 | "delayed-stream": { 233 | "version": "1.0.0", 234 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 235 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 236 | }, 237 | "doctrine": { 238 | "version": "1.5.0", 239 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", 240 | "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", 241 | "dev": true, 242 | "requires": { 243 | "esutils": "^2.0.2", 244 | "isarray": "^1.0.0" 245 | } 246 | }, 247 | "dom-serializer": { 248 | "version": "0.1.0", 249 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", 250 | "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", 251 | "requires": { 252 | "domelementtype": "~1.1.1", 253 | "entities": "~1.1.1" 254 | }, 255 | "dependencies": { 256 | "domelementtype": { 257 | "version": "1.1.3", 258 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", 259 | "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" 260 | } 261 | } 262 | }, 263 | "domelementtype": { 264 | "version": "1.3.0", 265 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", 266 | "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" 267 | }, 268 | "domhandler": { 269 | "version": "2.4.1", 270 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", 271 | "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", 272 | "requires": { 273 | "domelementtype": "1" 274 | } 275 | }, 276 | "domutils": { 277 | "version": "1.7.0", 278 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", 279 | "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", 280 | "requires": { 281 | "dom-serializer": "0", 282 | "domelementtype": "1" 283 | } 284 | }, 285 | "eachr": { 286 | "version": "2.0.4", 287 | "resolved": "https://registry.npmjs.org/eachr/-/eachr-2.0.4.tgz", 288 | "integrity": "sha1-Rm98qhBwj2EFCeMsgHqv5X/BIr8=", 289 | "requires": { 290 | "typechecker": "^2.0.8" 291 | } 292 | }, 293 | "ecc-jsbn": { 294 | "version": "0.1.2", 295 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 296 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 297 | "requires": { 298 | "jsbn": "~0.1.0", 299 | "safer-buffer": "^2.1.0" 300 | } 301 | }, 302 | "editions": { 303 | "version": "1.3.4", 304 | "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", 305 | "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==" 306 | }, 307 | "entities": { 308 | "version": "1.1.1", 309 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", 310 | "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" 311 | }, 312 | "eris": { 313 | "version": "0.11.0", 314 | "resolved": "https://registry.npmjs.org/eris/-/eris-0.11.0.tgz", 315 | "integrity": "sha512-fPLQj1BuOb4b5jQFAhoxLMjkmgFq53o9H8Q78dFXIUBVX9k2AbKO93MzstMfZi4UqaSI2Oz52RaM9kAsr7eJNg==", 316 | "requires": { 317 | "opusscript": "^0.0.4", 318 | "tweetnacl": "^1.0.0", 319 | "ws": "^7.1.2" 320 | }, 321 | "dependencies": { 322 | "tweetnacl": { 323 | "version": "1.0.1", 324 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz", 325 | "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==", 326 | "optional": true 327 | } 328 | } 329 | }, 330 | "error-ex": { 331 | "version": "1.3.2", 332 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 333 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 334 | "dev": true, 335 | "requires": { 336 | "is-arrayish": "^0.2.1" 337 | } 338 | }, 339 | "es-abstract": { 340 | "version": "1.13.0", 341 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", 342 | "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", 343 | "dev": true, 344 | "requires": { 345 | "es-to-primitive": "^1.2.0", 346 | "function-bind": "^1.1.1", 347 | "has": "^1.0.3", 348 | "is-callable": "^1.1.4", 349 | "is-regex": "^1.0.4", 350 | "object-keys": "^1.0.12" 351 | } 352 | }, 353 | "es-to-primitive": { 354 | "version": "1.2.0", 355 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", 356 | "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", 357 | "dev": true, 358 | "requires": { 359 | "is-callable": "^1.1.4", 360 | "is-date-object": "^1.0.1", 361 | "is-symbol": "^1.0.2" 362 | } 363 | }, 364 | "eslint-config-airbnb-base": { 365 | "version": "14.0.0", 366 | "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", 367 | "integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", 368 | "dev": true, 369 | "requires": { 370 | "confusing-browser-globals": "^1.0.7", 371 | "object.assign": "^4.1.0", 372 | "object.entries": "^1.1.0" 373 | } 374 | }, 375 | "eslint-config-google": { 376 | "version": "0.14.0", 377 | "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", 378 | "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", 379 | "dev": true 380 | }, 381 | "eslint-import-resolver-node": { 382 | "version": "0.3.2", 383 | "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", 384 | "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", 385 | "dev": true, 386 | "requires": { 387 | "debug": "^2.6.9", 388 | "resolve": "^1.5.0" 389 | } 390 | }, 391 | "eslint-module-utils": { 392 | "version": "2.4.1", 393 | "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", 394 | "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", 395 | "dev": true, 396 | "requires": { 397 | "debug": "^2.6.8", 398 | "pkg-dir": "^2.0.0" 399 | } 400 | }, 401 | "eslint-plugin-import": { 402 | "version": "2.18.2", 403 | "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", 404 | "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", 405 | "dev": true, 406 | "requires": { 407 | "array-includes": "^3.0.3", 408 | "contains-path": "^0.1.0", 409 | "debug": "^2.6.9", 410 | "doctrine": "1.5.0", 411 | "eslint-import-resolver-node": "^0.3.2", 412 | "eslint-module-utils": "^2.4.0", 413 | "has": "^1.0.3", 414 | "minimatch": "^3.0.4", 415 | "object.values": "^1.1.0", 416 | "read-pkg-up": "^2.0.0", 417 | "resolve": "^1.11.0" 418 | } 419 | }, 420 | "esutils": { 421 | "version": "2.0.3", 422 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 423 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 424 | "dev": true 425 | }, 426 | "extend": { 427 | "version": "3.0.2", 428 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 429 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 430 | }, 431 | "extendr": { 432 | "version": "2.1.0", 433 | "resolved": "https://registry.npmjs.org/extendr/-/extendr-2.1.0.tgz", 434 | "integrity": "sha1-MBqgu+pWX00tyPVw8qImEahSe1Y=", 435 | "requires": { 436 | "typechecker": "~2.0.1" 437 | }, 438 | "dependencies": { 439 | "typechecker": { 440 | "version": "2.0.8", 441 | "resolved": "https://registry.npmjs.org/typechecker/-/typechecker-2.0.8.tgz", 442 | "integrity": "sha1-6D2oS7ZMWEzLNFg4V2xAsDN9uC4=" 443 | } 444 | } 445 | }, 446 | "extract-opts": { 447 | "version": "2.2.0", 448 | "resolved": "https://registry.npmjs.org/extract-opts/-/extract-opts-2.2.0.tgz", 449 | "integrity": "sha1-H6KOunNSxttID4hc63GkaBC+bX0=", 450 | "requires": { 451 | "typechecker": "~2.0.1" 452 | }, 453 | "dependencies": { 454 | "typechecker": { 455 | "version": "2.0.8", 456 | "resolved": "https://registry.npmjs.org/typechecker/-/typechecker-2.0.8.tgz", 457 | "integrity": "sha1-6D2oS7ZMWEzLNFg4V2xAsDN9uC4=" 458 | } 459 | } 460 | }, 461 | "extsprintf": { 462 | "version": "1.3.0", 463 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 464 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 465 | }, 466 | "fast-deep-equal": { 467 | "version": "2.0.1", 468 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 469 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 470 | }, 471 | "fast-json-stable-stringify": { 472 | "version": "2.0.0", 473 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 474 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 475 | }, 476 | "find-up": { 477 | "version": "2.1.0", 478 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 479 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 480 | "dev": true, 481 | "requires": { 482 | "locate-path": "^2.0.0" 483 | } 484 | }, 485 | "forever-agent": { 486 | "version": "0.6.1", 487 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 488 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 489 | }, 490 | "form-data": { 491 | "version": "2.3.3", 492 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 493 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 494 | "requires": { 495 | "asynckit": "^0.4.0", 496 | "combined-stream": "^1.0.6", 497 | "mime-types": "^2.1.12" 498 | } 499 | }, 500 | "function-bind": { 501 | "version": "1.1.1", 502 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 503 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 504 | "dev": true 505 | }, 506 | "getpass": { 507 | "version": "0.1.7", 508 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 509 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 510 | "requires": { 511 | "assert-plus": "^1.0.0" 512 | } 513 | }, 514 | "glob": { 515 | "version": "6.0.4", 516 | "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", 517 | "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", 518 | "requires": { 519 | "inflight": "^1.0.4", 520 | "inherits": "2", 521 | "minimatch": "2 || 3", 522 | "once": "^1.3.0", 523 | "path-is-absolute": "^1.0.0" 524 | } 525 | }, 526 | "graceful-fs": { 527 | "version": "4.1.11", 528 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 529 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 530 | }, 531 | "har-schema": { 532 | "version": "2.0.0", 533 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 534 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 535 | }, 536 | "har-validator": { 537 | "version": "5.1.3", 538 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 539 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 540 | "requires": { 541 | "ajv": "^6.5.5", 542 | "har-schema": "^2.0.0" 543 | } 544 | }, 545 | "has": { 546 | "version": "1.0.3", 547 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 548 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 549 | "dev": true, 550 | "requires": { 551 | "function-bind": "^1.1.1" 552 | } 553 | }, 554 | "has-symbols": { 555 | "version": "1.0.0", 556 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 557 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", 558 | "dev": true 559 | }, 560 | "he": { 561 | "version": "1.2.0", 562 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 563 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" 564 | }, 565 | "hosted-git-info": { 566 | "version": "2.8.5", 567 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", 568 | "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", 569 | "dev": true 570 | }, 571 | "html-to-text": { 572 | "version": "5.1.1", 573 | "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-5.1.1.tgz", 574 | "integrity": "sha512-Bci6bD/JIfZSvG4s0gW/9mMKwBRoe/1RWLxUME/d6WUSZCdY7T60bssf/jFf7EYXRyqU4P5xdClVqiYU0/ypdA==", 575 | "requires": { 576 | "he": "^1.2.0", 577 | "htmlparser2": "^3.10.1", 578 | "lodash": "^4.17.11", 579 | "minimist": "^1.2.0" 580 | } 581 | }, 582 | "html2plaintext": { 583 | "version": "2.1.2", 584 | "resolved": "https://registry.npmjs.org/html2plaintext/-/html2plaintext-2.1.2.tgz", 585 | "integrity": "sha512-/7rk161q0RFtQhu0F7oU7MFUtqjm2qBrVfoS8EOaHSdRNt72CNNYSV1/wN+TfO2GhgLQdIjPctmiWPX3oRcNFQ==", 586 | "requires": { 587 | "cheerio": "1.0.0-rc.2", 588 | "he": "1.2.0", 589 | "plumb": "0.1.0" 590 | } 591 | }, 592 | "htmlparser2": { 593 | "version": "3.10.1", 594 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", 595 | "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", 596 | "requires": { 597 | "domelementtype": "^1.3.1", 598 | "domhandler": "^2.3.0", 599 | "domutils": "^1.5.1", 600 | "entities": "^1.1.1", 601 | "inherits": "^2.0.1", 602 | "readable-stream": "^3.1.1" 603 | }, 604 | "dependencies": { 605 | "domelementtype": { 606 | "version": "1.3.1", 607 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", 608 | "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" 609 | } 610 | } 611 | }, 612 | "http-signature": { 613 | "version": "1.2.0", 614 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 615 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 616 | "requires": { 617 | "assert-plus": "^1.0.0", 618 | "jsprim": "^1.2.2", 619 | "sshpk": "^1.7.0" 620 | } 621 | }, 622 | "i18n": { 623 | "version": "0.8.3", 624 | "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.8.3.tgz", 625 | "integrity": "sha1-LYzxwkciYCwgQdAbpq5eqlE4jw4=", 626 | "requires": { 627 | "debug": "*", 628 | "make-plural": "^3.0.3", 629 | "math-interval-parser": "^1.1.0", 630 | "messageformat": "^0.3.1", 631 | "mustache": "*", 632 | "sprintf-js": ">=1.0.3" 633 | } 634 | }, 635 | "iconv-lite": { 636 | "version": "0.4.24", 637 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 638 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 639 | "requires": { 640 | "safer-buffer": ">= 2.1.2 < 3" 641 | } 642 | }, 643 | "ignorefs": { 644 | "version": "1.2.0", 645 | "resolved": "https://registry.npmjs.org/ignorefs/-/ignorefs-1.2.0.tgz", 646 | "integrity": "sha1-2ln7hYl25KXkNwLM0fKC/byeV1Y=", 647 | "requires": { 648 | "editions": "^1.3.3", 649 | "ignorepatterns": "^1.1.0" 650 | } 651 | }, 652 | "ignorepatterns": { 653 | "version": "1.1.0", 654 | "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-1.1.0.tgz", 655 | "integrity": "sha1-rI9DbyI5td+2bV8NOpBKh6xnzF4=" 656 | }, 657 | "immediate": { 658 | "version": "3.0.6", 659 | "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", 660 | "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" 661 | }, 662 | "inflight": { 663 | "version": "1.0.6", 664 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 665 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 666 | "requires": { 667 | "once": "^1.3.0", 668 | "wrappy": "1" 669 | } 670 | }, 671 | "inherits": { 672 | "version": "2.0.3", 673 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 674 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 675 | }, 676 | "int64-buffer": { 677 | "version": "0.99.1007", 678 | "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.99.1007.tgz", 679 | "integrity": "sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==" 680 | }, 681 | "ipv6-normalize": { 682 | "version": "1.0.1", 683 | "resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz", 684 | "integrity": "sha1-GzJYKQ02X6gyOeiZB93kWS52IKg=" 685 | }, 686 | "is-arrayish": { 687 | "version": "0.2.1", 688 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 689 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 690 | "dev": true 691 | }, 692 | "is-callable": { 693 | "version": "1.1.4", 694 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 695 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", 696 | "dev": true 697 | }, 698 | "is-date-object": { 699 | "version": "1.0.1", 700 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 701 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", 702 | "dev": true 703 | }, 704 | "is-regex": { 705 | "version": "1.0.4", 706 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 707 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 708 | "dev": true, 709 | "requires": { 710 | "has": "^1.0.1" 711 | } 712 | }, 713 | "is-symbol": { 714 | "version": "1.0.2", 715 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", 716 | "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", 717 | "dev": true, 718 | "requires": { 719 | "has-symbols": "^1.0.0" 720 | } 721 | }, 722 | "is-typedarray": { 723 | "version": "1.0.0", 724 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 725 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 726 | }, 727 | "isarray": { 728 | "version": "1.0.0", 729 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 730 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 731 | }, 732 | "isstream": { 733 | "version": "0.1.2", 734 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 735 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 736 | }, 737 | "jsbn": { 738 | "version": "0.1.1", 739 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 740 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 741 | }, 742 | "json-schema": { 743 | "version": "0.2.3", 744 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 745 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 746 | }, 747 | "json-schema-traverse": { 748 | "version": "0.4.1", 749 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 750 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 751 | }, 752 | "json-stringify-safe": { 753 | "version": "5.0.1", 754 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 755 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 756 | }, 757 | "jsprim": { 758 | "version": "1.4.1", 759 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 760 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 761 | "requires": { 762 | "assert-plus": "1.0.0", 763 | "extsprintf": "1.3.0", 764 | "json-schema": "0.2.3", 765 | "verror": "1.10.0" 766 | } 767 | }, 768 | "jszip": { 769 | "version": "3.2.2", 770 | "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.2.tgz", 771 | "integrity": "sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==", 772 | "requires": { 773 | "lie": "~3.3.0", 774 | "pako": "~1.0.2", 775 | "readable-stream": "~2.3.6", 776 | "set-immediate-shim": "~1.0.1" 777 | }, 778 | "dependencies": { 779 | "readable-stream": { 780 | "version": "2.3.6", 781 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 782 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 783 | "requires": { 784 | "core-util-is": "~1.0.0", 785 | "inherits": "~2.0.3", 786 | "isarray": "~1.0.0", 787 | "process-nextick-args": "~2.0.0", 788 | "safe-buffer": "~5.1.1", 789 | "string_decoder": "~1.1.1", 790 | "util-deprecate": "~1.0.1" 791 | } 792 | }, 793 | "string_decoder": { 794 | "version": "1.1.1", 795 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 796 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 797 | "requires": { 798 | "safe-buffer": "~5.1.0" 799 | } 800 | } 801 | } 802 | }, 803 | "libbase64": { 804 | "version": "1.0.3", 805 | "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.0.3.tgz", 806 | "integrity": "sha512-ULQZAATVGTAgVNwP61R+MbbSGNBy1tVzWupB9kbE6p+VccWd+J+ICXgOwQic5Yqagzpu+oPZ8sI7yXdWJnPPkA==" 807 | }, 808 | "libmime": { 809 | "version": "4.1.1", 810 | "resolved": "https://registry.npmjs.org/libmime/-/libmime-4.1.1.tgz", 811 | "integrity": "sha512-HkOfBSj+l7pBOOucEgiI6PdbgHa8ljv+1rARzW743HQ51UP8gabMlcA2wAF3Dg1aeuMjHZ+LzAPYxM52IZsyGA==", 812 | "requires": { 813 | "iconv-lite": "0.4.24", 814 | "libbase64": "1.0.3", 815 | "libqp": "1.1.0" 816 | } 817 | }, 818 | "libqp": { 819 | "version": "1.1.0", 820 | "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", 821 | "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=" 822 | }, 823 | "lie": { 824 | "version": "3.3.0", 825 | "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", 826 | "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", 827 | "requires": { 828 | "immediate": "~3.0.5" 829 | } 830 | }, 831 | "linkify-it": { 832 | "version": "2.1.0", 833 | "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.1.0.tgz", 834 | "integrity": "sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==", 835 | "requires": { 836 | "uc.micro": "^1.0.1" 837 | } 838 | }, 839 | "load-json-file": { 840 | "version": "2.0.0", 841 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", 842 | "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", 843 | "dev": true, 844 | "requires": { 845 | "graceful-fs": "^4.1.2", 846 | "parse-json": "^2.2.0", 847 | "pify": "^2.0.0", 848 | "strip-bom": "^3.0.0" 849 | } 850 | }, 851 | "locate-path": { 852 | "version": "2.0.0", 853 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 854 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 855 | "dev": true, 856 | "requires": { 857 | "p-locate": "^2.0.0", 858 | "path-exists": "^3.0.0" 859 | } 860 | }, 861 | "lodash": { 862 | "version": "4.17.15", 863 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 864 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" 865 | }, 866 | "mailparser": { 867 | "version": "2.7.1", 868 | "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-2.7.1.tgz", 869 | "integrity": "sha512-qAyDPuyd0ygTM3V9yzxVilYyRt0mpjLmp6OSzBPjwMZYX1PVDOoGEyUgDtyCDoEgC5fqslpXpWCI6t7RN3i3fw==", 870 | "requires": { 871 | "he": "1.2.0", 872 | "html-to-text": "5.1.1", 873 | "iconv-lite": "0.4.24", 874 | "libmime": "4.1.1", 875 | "linkify-it": "2.1.0", 876 | "mailsplit": "4.4.1", 877 | "nodemailer": "6.1.1", 878 | "tlds": "1.203.1" 879 | }, 880 | "dependencies": { 881 | "nodemailer": { 882 | "version": "6.1.1", 883 | "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.1.1.tgz", 884 | "integrity": "sha512-/x5MRIh56VyuuhLfcz+DL2SlBARpZpgQIf2A4Ao4hMb69MHSgDIMPwYmFwesGT1lkRDZ0eBSoym5+JoIZ3N+cQ==" 885 | } 886 | } 887 | }, 888 | "mailsplit": { 889 | "version": "4.4.1", 890 | "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-4.4.1.tgz", 891 | "integrity": "sha512-AmWLEHQAg/zbNb1MdrPQS9VOzysHaU9IuoQV9kGU5fgjM5RCbgqVkZzp0+DhPep8sj8iHfbWkl16Nb1PbNlTYg==", 892 | "requires": { 893 | "libbase64": "1.0.3", 894 | "libmime": "4.1.1", 895 | "libqp": "1.1.0" 896 | } 897 | }, 898 | "make-plural": { 899 | "version": "3.0.6", 900 | "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-3.0.6.tgz", 901 | "integrity": "sha1-IDOgO6wpC487uRJY9lud9+iwHKc=", 902 | "requires": { 903 | "minimist": "^1.2.0" 904 | }, 905 | "dependencies": { 906 | "minimist": { 907 | "version": "1.2.0", 908 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 909 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 910 | "optional": true 911 | } 912 | } 913 | }, 914 | "math-interval-parser": { 915 | "version": "1.1.0", 916 | "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-1.1.0.tgz", 917 | "integrity": "sha1-2+2lsGsySZc8bfYXD94jhvCv2JM=", 918 | "requires": { 919 | "xregexp": "^2.0.0" 920 | } 921 | }, 922 | "messageformat": { 923 | "version": "0.3.1", 924 | "resolved": "https://registry.npmjs.org/messageformat/-/messageformat-0.3.1.tgz", 925 | "integrity": "sha1-5Y//gkXps5cXmeW0PbWLPpQX9aI=", 926 | "requires": { 927 | "async": "~1.5.2", 928 | "glob": "~6.0.4", 929 | "make-plural": "~3.0.3", 930 | "nopt": "~3.0.6", 931 | "watchr": "~2.4.13" 932 | } 933 | }, 934 | "mime-db": { 935 | "version": "1.38.0", 936 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", 937 | "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" 938 | }, 939 | "mime-types": { 940 | "version": "2.1.22", 941 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", 942 | "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", 943 | "requires": { 944 | "mime-db": "~1.38.0" 945 | } 946 | }, 947 | "minimatch": { 948 | "version": "3.0.4", 949 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 950 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 951 | "requires": { 952 | "brace-expansion": "^1.1.7" 953 | } 954 | }, 955 | "minimist": { 956 | "version": "1.2.0", 957 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 958 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 959 | }, 960 | "ms": { 961 | "version": "2.0.0", 962 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 963 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 964 | }, 965 | "mustache": { 966 | "version": "2.3.0", 967 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", 968 | "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=" 969 | }, 970 | "node-fetch": { 971 | "version": "2.6.0", 972 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 973 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" 974 | }, 975 | "nodemailer": { 976 | "version": "5.0.0", 977 | "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-5.0.0.tgz", 978 | "integrity": "sha512-XI4PI5L7GYcJyHkPcHlvPyRrYohNYBNRNbt1tU8PXNU3E1ADJC84a13V0vbL9AM431OP+ETacaGXAF8fGn1JvA==" 979 | }, 980 | "nopt": { 981 | "version": "3.0.6", 982 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", 983 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 984 | "requires": { 985 | "abbrev": "1" 986 | } 987 | }, 988 | "normalize-package-data": { 989 | "version": "2.5.0", 990 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 991 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 992 | "dev": true, 993 | "requires": { 994 | "hosted-git-info": "^2.1.4", 995 | "resolve": "^1.10.0", 996 | "semver": "2 || 3 || 4 || 5", 997 | "validate-npm-package-license": "^3.0.1" 998 | } 999 | }, 1000 | "nth-check": { 1001 | "version": "1.0.2", 1002 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", 1003 | "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", 1004 | "requires": { 1005 | "boolbase": "~1.0.0" 1006 | } 1007 | }, 1008 | "oauth-sign": { 1009 | "version": "0.9.0", 1010 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 1011 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 1012 | }, 1013 | "object-keys": { 1014 | "version": "1.1.1", 1015 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1016 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 1017 | "dev": true 1018 | }, 1019 | "object.assign": { 1020 | "version": "4.1.0", 1021 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 1022 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 1023 | "dev": true, 1024 | "requires": { 1025 | "define-properties": "^1.1.2", 1026 | "function-bind": "^1.1.1", 1027 | "has-symbols": "^1.0.0", 1028 | "object-keys": "^1.0.11" 1029 | } 1030 | }, 1031 | "object.entries": { 1032 | "version": "1.1.0", 1033 | "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", 1034 | "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", 1035 | "dev": true, 1036 | "requires": { 1037 | "define-properties": "^1.1.3", 1038 | "es-abstract": "^1.12.0", 1039 | "function-bind": "^1.1.1", 1040 | "has": "^1.0.3" 1041 | } 1042 | }, 1043 | "object.values": { 1044 | "version": "1.1.0", 1045 | "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", 1046 | "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", 1047 | "dev": true, 1048 | "requires": { 1049 | "define-properties": "^1.1.3", 1050 | "es-abstract": "^1.12.0", 1051 | "function-bind": "^1.1.1", 1052 | "has": "^1.0.3" 1053 | } 1054 | }, 1055 | "once": { 1056 | "version": "1.4.0", 1057 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1058 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1059 | "requires": { 1060 | "wrappy": "1" 1061 | } 1062 | }, 1063 | "opusscript": { 1064 | "version": "0.0.4", 1065 | "resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.0.4.tgz", 1066 | "integrity": "sha512-bEPZFE2lhUJYQD5yfTFO4RhbRZ937x6hRwBC1YoGacT35bwDVwKFP1+amU8NYfZL/v4EU7ZTU3INTqzYAnuP7Q==", 1067 | "optional": true 1068 | }, 1069 | "p-limit": { 1070 | "version": "1.3.0", 1071 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 1072 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 1073 | "dev": true, 1074 | "requires": { 1075 | "p-try": "^1.0.0" 1076 | } 1077 | }, 1078 | "p-locate": { 1079 | "version": "2.0.0", 1080 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 1081 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 1082 | "dev": true, 1083 | "requires": { 1084 | "p-limit": "^1.1.0" 1085 | } 1086 | }, 1087 | "p-try": { 1088 | "version": "1.0.0", 1089 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 1090 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 1091 | "dev": true 1092 | }, 1093 | "pako": { 1094 | "version": "1.0.10", 1095 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", 1096 | "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" 1097 | }, 1098 | "parse-json": { 1099 | "version": "2.2.0", 1100 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 1101 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 1102 | "dev": true, 1103 | "requires": { 1104 | "error-ex": "^1.2.0" 1105 | } 1106 | }, 1107 | "parse5": { 1108 | "version": "3.0.3", 1109 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", 1110 | "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", 1111 | "requires": { 1112 | "@types/node": "*" 1113 | } 1114 | }, 1115 | "path-exists": { 1116 | "version": "3.0.0", 1117 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1118 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1119 | "dev": true 1120 | }, 1121 | "path-is-absolute": { 1122 | "version": "1.0.1", 1123 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1124 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1125 | }, 1126 | "path-parse": { 1127 | "version": "1.0.6", 1128 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1129 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1130 | "dev": true 1131 | }, 1132 | "path-type": { 1133 | "version": "2.0.0", 1134 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", 1135 | "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", 1136 | "dev": true, 1137 | "requires": { 1138 | "pify": "^2.0.0" 1139 | } 1140 | }, 1141 | "performance-now": { 1142 | "version": "2.1.0", 1143 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 1144 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 1145 | }, 1146 | "pify": { 1147 | "version": "2.3.0", 1148 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1149 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 1150 | "dev": true 1151 | }, 1152 | "pkg-dir": { 1153 | "version": "2.0.0", 1154 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", 1155 | "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", 1156 | "dev": true, 1157 | "requires": { 1158 | "find-up": "^2.1.0" 1159 | } 1160 | }, 1161 | "plumb": { 1162 | "version": "0.1.0", 1163 | "resolved": "https://registry.npmjs.org/plumb/-/plumb-0.1.0.tgz", 1164 | "integrity": "sha1-TFd5ClCWkoMv2/EN+t3XlIxctXQ=" 1165 | }, 1166 | "process-nextick-args": { 1167 | "version": "2.0.1", 1168 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1169 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 1170 | }, 1171 | "psl": { 1172 | "version": "1.1.31", 1173 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", 1174 | "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" 1175 | }, 1176 | "punycode": { 1177 | "version": "1.4.1", 1178 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 1179 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 1180 | }, 1181 | "qs": { 1182 | "version": "6.5.2", 1183 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 1184 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 1185 | }, 1186 | "read-pkg": { 1187 | "version": "2.0.0", 1188 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", 1189 | "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", 1190 | "dev": true, 1191 | "requires": { 1192 | "load-json-file": "^2.0.0", 1193 | "normalize-package-data": "^2.3.2", 1194 | "path-type": "^2.0.0" 1195 | } 1196 | }, 1197 | "read-pkg-up": { 1198 | "version": "2.0.0", 1199 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", 1200 | "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", 1201 | "dev": true, 1202 | "requires": { 1203 | "find-up": "^2.0.0", 1204 | "read-pkg": "^2.0.0" 1205 | } 1206 | }, 1207 | "readable-stream": { 1208 | "version": "3.3.0", 1209 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", 1210 | "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", 1211 | "requires": { 1212 | "inherits": "^2.0.3", 1213 | "string_decoder": "^1.1.1", 1214 | "util-deprecate": "^1.0.1" 1215 | } 1216 | }, 1217 | "request": { 1218 | "version": "2.88.0", 1219 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 1220 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 1221 | "requires": { 1222 | "aws-sign2": "~0.7.0", 1223 | "aws4": "^1.8.0", 1224 | "caseless": "~0.12.0", 1225 | "combined-stream": "~1.0.6", 1226 | "extend": "~3.0.2", 1227 | "forever-agent": "~0.6.1", 1228 | "form-data": "~2.3.2", 1229 | "har-validator": "~5.1.0", 1230 | "http-signature": "~1.2.0", 1231 | "is-typedarray": "~1.0.0", 1232 | "isstream": "~0.1.2", 1233 | "json-stringify-safe": "~5.0.1", 1234 | "mime-types": "~2.1.19", 1235 | "oauth-sign": "~0.9.0", 1236 | "performance-now": "^2.1.0", 1237 | "qs": "~6.5.2", 1238 | "safe-buffer": "^5.1.2", 1239 | "tough-cookie": "~2.4.3", 1240 | "tunnel-agent": "^0.6.0", 1241 | "uuid": "^3.3.2" 1242 | }, 1243 | "dependencies": { 1244 | "safe-buffer": { 1245 | "version": "5.1.2", 1246 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1247 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1248 | } 1249 | } 1250 | }, 1251 | "resolve": { 1252 | "version": "1.12.0", 1253 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", 1254 | "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", 1255 | "dev": true, 1256 | "requires": { 1257 | "path-parse": "^1.0.6" 1258 | } 1259 | }, 1260 | "safe-buffer": { 1261 | "version": "5.1.1", 1262 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 1263 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 1264 | }, 1265 | "safefs": { 1266 | "version": "3.2.2", 1267 | "resolved": "https://registry.npmjs.org/safefs/-/safefs-3.2.2.tgz", 1268 | "integrity": "sha1-gXDBRE1wOOCMrqBaN0+uL6NJ4Vw=", 1269 | "requires": { 1270 | "graceful-fs": "*" 1271 | } 1272 | }, 1273 | "safer-buffer": { 1274 | "version": "2.1.2", 1275 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1276 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1277 | }, 1278 | "scandirectory": { 1279 | "version": "2.5.0", 1280 | "resolved": "https://registry.npmjs.org/scandirectory/-/scandirectory-2.5.0.tgz", 1281 | "integrity": "sha1-bOA/VKCQtmjjy+2/IO354xBZPnI=", 1282 | "requires": { 1283 | "ignorefs": "^1.0.0", 1284 | "safefs": "^3.1.2", 1285 | "taskgroup": "^4.0.5" 1286 | } 1287 | }, 1288 | "semver": { 1289 | "version": "5.7.1", 1290 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 1291 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 1292 | "dev": true 1293 | }, 1294 | "set-immediate-shim": { 1295 | "version": "1.0.1", 1296 | "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", 1297 | "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" 1298 | }, 1299 | "smtp-server": { 1300 | "version": "3.5.0", 1301 | "resolved": "https://registry.npmjs.org/smtp-server/-/smtp-server-3.5.0.tgz", 1302 | "integrity": "sha512-7FUg09H1VmqMRlUq/QdkPxn/NK8VCFw7GMU5rdWWDbS00wbLhjRBe3Lme+AamjDSmVoP6e/WqFqsa7jVI+69pg==", 1303 | "requires": { 1304 | "base32.js": "0.1.0", 1305 | "ipv6-normalize": "1.0.1", 1306 | "nodemailer": "5.0.0" 1307 | } 1308 | }, 1309 | "spdx-correct": { 1310 | "version": "3.1.0", 1311 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", 1312 | "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", 1313 | "dev": true, 1314 | "requires": { 1315 | "spdx-expression-parse": "^3.0.0", 1316 | "spdx-license-ids": "^3.0.0" 1317 | } 1318 | }, 1319 | "spdx-exceptions": { 1320 | "version": "2.2.0", 1321 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", 1322 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", 1323 | "dev": true 1324 | }, 1325 | "spdx-expression-parse": { 1326 | "version": "3.0.0", 1327 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", 1328 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", 1329 | "dev": true, 1330 | "requires": { 1331 | "spdx-exceptions": "^2.1.0", 1332 | "spdx-license-ids": "^3.0.0" 1333 | } 1334 | }, 1335 | "spdx-license-ids": { 1336 | "version": "3.0.5", 1337 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", 1338 | "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", 1339 | "dev": true 1340 | }, 1341 | "sprintf-js": { 1342 | "version": "1.1.1", 1343 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", 1344 | "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=" 1345 | }, 1346 | "sshpk": { 1347 | "version": "1.16.1", 1348 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 1349 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 1350 | "requires": { 1351 | "asn1": "~0.2.3", 1352 | "assert-plus": "^1.0.0", 1353 | "bcrypt-pbkdf": "^1.0.0", 1354 | "dashdash": "^1.12.0", 1355 | "ecc-jsbn": "~0.1.1", 1356 | "getpass": "^0.1.1", 1357 | "jsbn": "~0.1.0", 1358 | "safer-buffer": "^2.0.2", 1359 | "tweetnacl": "~0.14.0" 1360 | } 1361 | }, 1362 | "string_decoder": { 1363 | "version": "1.2.0", 1364 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", 1365 | "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", 1366 | "requires": { 1367 | "safe-buffer": "~5.1.0" 1368 | } 1369 | }, 1370 | "strip-bom": { 1371 | "version": "3.0.0", 1372 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1373 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 1374 | "dev": true 1375 | }, 1376 | "taskgroup": { 1377 | "version": "4.3.1", 1378 | "resolved": "https://registry.npmjs.org/taskgroup/-/taskgroup-4.3.1.tgz", 1379 | "integrity": "sha1-feGT/r12gnPEV3MElwJNUSwnkVo=", 1380 | "requires": { 1381 | "ambi": "^2.2.0", 1382 | "csextends": "^1.0.3" 1383 | } 1384 | }, 1385 | "tlds": { 1386 | "version": "1.203.1", 1387 | "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.203.1.tgz", 1388 | "integrity": "sha512-7MUlYyGJ6rSitEZ3r1Q1QNV8uSIzapS8SmmhSusBuIc7uIxPPwsKllEP0GRp1NS6Ik6F+fRZvnjDWm3ecv2hDw==" 1389 | }, 1390 | "tough-cookie": { 1391 | "version": "2.4.3", 1392 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 1393 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 1394 | "requires": { 1395 | "psl": "^1.1.24", 1396 | "punycode": "^1.4.1" 1397 | } 1398 | }, 1399 | "tunnel-agent": { 1400 | "version": "0.6.0", 1401 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1402 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 1403 | "requires": { 1404 | "safe-buffer": "^5.0.1" 1405 | } 1406 | }, 1407 | "tweetnacl": { 1408 | "version": "0.14.5", 1409 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 1410 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 1411 | }, 1412 | "typechecker": { 1413 | "version": "2.1.0", 1414 | "resolved": "https://registry.npmjs.org/typechecker/-/typechecker-2.1.0.tgz", 1415 | "integrity": "sha1-0cIJOlT/ihn1jP+HfuqlTyJC04M=" 1416 | }, 1417 | "uc.micro": { 1418 | "version": "1.0.6", 1419 | "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", 1420 | "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" 1421 | }, 1422 | "uri-js": { 1423 | "version": "4.2.2", 1424 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1425 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1426 | "requires": { 1427 | "punycode": "^2.1.0" 1428 | }, 1429 | "dependencies": { 1430 | "punycode": { 1431 | "version": "2.1.1", 1432 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1433 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 1434 | } 1435 | } 1436 | }, 1437 | "util-deprecate": { 1438 | "version": "1.0.2", 1439 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1440 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1441 | }, 1442 | "uuid": { 1443 | "version": "3.3.2", 1444 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 1445 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 1446 | }, 1447 | "validate-npm-package-license": { 1448 | "version": "3.0.4", 1449 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 1450 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 1451 | "dev": true, 1452 | "requires": { 1453 | "spdx-correct": "^3.0.0", 1454 | "spdx-expression-parse": "^3.0.0" 1455 | } 1456 | }, 1457 | "verror": { 1458 | "version": "1.10.0", 1459 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1460 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 1461 | "requires": { 1462 | "assert-plus": "^1.0.0", 1463 | "core-util-is": "1.0.2", 1464 | "extsprintf": "^1.2.0" 1465 | } 1466 | }, 1467 | "watchr": { 1468 | "version": "2.4.13", 1469 | "resolved": "https://registry.npmjs.org/watchr/-/watchr-2.4.13.tgz", 1470 | "integrity": "sha1-10hHu01vkPYf4sdPn2hmKqDgdgE=", 1471 | "requires": { 1472 | "eachr": "^2.0.2", 1473 | "extendr": "^2.1.0", 1474 | "extract-opts": "^2.2.0", 1475 | "ignorefs": "^1.0.0", 1476 | "safefs": "^3.1.2", 1477 | "scandirectory": "^2.5.0", 1478 | "taskgroup": "^4.2.0", 1479 | "typechecker": "^2.0.8" 1480 | } 1481 | }, 1482 | "wrappy": { 1483 | "version": "1.0.2", 1484 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1485 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1486 | }, 1487 | "ws": { 1488 | "version": "7.1.2", 1489 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz", 1490 | "integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==", 1491 | "requires": { 1492 | "async-limiter": "^1.0.0" 1493 | } 1494 | }, 1495 | "xregexp": { 1496 | "version": "2.0.0", 1497 | "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", 1498 | "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" 1499 | } 1500 | } 1501 | } 1502 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discordmailhooks", 3 | "version": "1.0.0", 4 | "description": "An E-Mail to Discord Webhooks mail server for recieving only", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Moustacheminer Server Services", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "eslint-config-airbnb-base": "^14.0.0", 13 | "eslint-config-google": "^0.14.0", 14 | "eslint-plugin-import": "^2.18.2" 15 | }, 16 | "dependencies": { 17 | "eris": "^0.11.0", 18 | "html2plaintext": "^2.1.2", 19 | "i18n": "^0.8.3", 20 | "int64-buffer": "^0.99.1007", 21 | "jszip": "^3.2.2", 22 | "mailparser": "^2.7.1", 23 | "node-fetch": "^2.6.0", 24 | "request": "^2.88.0", 25 | "smtp-server": "^3.5.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test.ps1: -------------------------------------------------------------------------------- 1 | $smtpServer = "discordmail.com" 2 | $smtpFrom = "me@discord.pw" 3 | $smtpTo = "lepeli@discordmail.com" 4 | $messageSubject = "Congratulations" 5 | $messageBody = "You won a free XSS website!" 6 | 7 | $smtp = New-Object Net.Mail.SmtpClient($smtpServer) 8 | $smtp.Send($smtpFrom,$smtpTo,$messagesubject,$messagebody) 9 | --------------------------------------------------------------------------------