Add CsrfProtectionComponent tests and fix missing promise await

This commit is contained in:
Alice Gaudon 2020-07-08 10:49:29 +02:00
parent 001e24488b
commit afdfadd34e
22 changed files with 915 additions and 23 deletions

View File

@ -3,7 +3,7 @@ export default {
host: "localhost",
user: "root",
password: "",
database: "wms2_test",
database: "wms2_core_test",
create_database_automatically: true
}
};

View File

@ -1,6 +1,6 @@
{
"name": "wms-core",
"version": "0.10.20",
"version": "0.10.21",
"description": "Node web framework",
"repository": "git@gitlab.com:ArisuOngaku/wms-core.git",
"author": "Alice Gaudon <alice@gaudon.pro>",
@ -26,9 +26,12 @@
"@types/geoip-lite": "^1.1.31",
"@types/jest": "^25.2.1",
"@types/mjml": "^4.0.4",
"@types/node-fetch": "^2.5.7",
"@types/on-finished": "^2.3.1",
"@types/uuid": "^7.0.2",
"jest": "^25.4.0",
"maildev": "^1.1.0",
"node-fetch": "^2.6.0",
"ts-jest": "^25.4.0",
"typescript": "^3.8.3"
},

View File

@ -5,7 +5,7 @@ import {BadRequestError} from "../HttpError";
export default class CsrfProtectionComponent extends ApplicationComponent<void> {
public async start(app: Express, router: Router): Promise<void> {
router.use((req, res, next) => {
router.use(async (req, res, next) => {
if (!req.session) {
throw new Error('Session is unavailable.');
}
@ -17,7 +17,9 @@ export default class CsrfProtectionComponent extends ApplicationComponent<void>
return req.session!.csrf;
};
if (!['GET', 'HEAD', 'OPTIONS'].find(s => s === req.method) && !req.authGuard.isAuthenticatedViaRequest(req)) {
if (!['GET', 'HEAD', 'OPTIONS'].find(s => s === req.method)) {
try {
if (!(await req.authGuard.isAuthenticatedViaRequest(req))) {
if (req.session.csrf === undefined) {
throw new InvalidCsrfTokenError(req.baseUrl, `You weren't assigned any CSRF token.`);
} else if (req.body.csrf === undefined) {
@ -26,6 +28,11 @@ export default class CsrfProtectionComponent extends ApplicationComponent<void>
throw new InvalidCsrfTokenError(req.baseUrl, `Tokens don't match.`);
}
}
} catch (e) {
next(e);
return;
}
}
next();
});
}

View File

@ -6,8 +6,15 @@ import Controller from "../Controller";
import {ServerError} from "../HttpError";
export default class NunjucksComponent extends ApplicationComponent<void> {
private readonly viewsPath: string;
constructor(viewsPath: string = 'views') {
super();
this.viewsPath = viewsPath;
}
public async start(app: Express, router: Router): Promise<void> {
const env = nunjucks.configure('views', {
const env = nunjucks.configure(this.viewsPath, {
autoescape: true,
express: app,
noCache: !config.get('view.cache'),
@ -19,7 +26,7 @@ export default class NunjucksComponent extends ApplicationComponent<void> {
return path;
})
.addGlobal('app_version', this.app!.getVersion())
.addGlobal('core_version', require('../package.json').version)
.addGlobal('core_version', require('../../package.json').version)
.addFilter('hex', (v: number) => {
return v.toString(16);
});

View File

@ -0,0 +1,117 @@
import fetch, {Response} from "node-fetch";
import useApp, {DEFAULT_ADDR, TestApp} from "./_app";
import Controller from "../src/Controller";
import CsrfProtectionComponent from "../src/components/CsrfProtectionComponent";
useApp(port => {
return new class extends TestApp {
protected async init(): Promise<void> {
this.use(new class extends Controller {
routes(): void {
this.get('/', (req, res, next) => {
res.render('test/csrf.njk');
}, 'csrf_test');
this.post('/', (req, res, next) => {
res.json({
status: 'ok',
});
}, 'csrf_test');
}
}());
await super.init();
}
protected registerComponents() {
super.registerComponents();
this.use(new CsrfProtectionComponent());
}
}(port);
});
describe('Test CSRF protection', () => {
let res: Response;
test('no csrf token should be in session at first', async () => {
res = await fetch(DEFAULT_ADDR, {
method: 'POST',
});
expect(res.status).toBe(401);
expect(await res.text()).toContain(`You weren't assigned any CSRF token.`);
});
let cookies: string | null;
test('sending no csrf token should fail', async () => {
cookies = res.headers.get('set-cookie');
expect(cookies).toBeDefined();
res = await fetch(`${DEFAULT_ADDR}${Controller.route('csrf_test')}`, {
headers: {
'Cookie': cookies!,
}
});
expect(res.ok).toBe(true);
res = await fetch(DEFAULT_ADDR, {
method: 'POST',
headers: {
'Cookie': cookies!,
}
});
expect(res.status).toBe(401);
expect(await res.text()).toContain(`You didn't provide any CSRF token.`);
});
test('sending an invalid csrf token should fail', async () => {
cookies = res.headers.get('set-cookie');
expect(cookies).toBeDefined();
res = await fetch(`${DEFAULT_ADDR}${Controller.route('csrf_test')}`, {
headers: {
'Cookie': cookies!,
}
});
expect(res.ok).toBe(true);
res = await fetch(DEFAULT_ADDR, {
method: 'POST',
body: JSON.stringify({
csrf: 'not_a_valid_csrf',
}),
headers: {
'Content-Type': 'application/json',
'Cookie': cookies!,
}
});
expect(res.status).toBe(401);
expect(await res.text()).toContain(`Tokens don't match.`);
});
test('sending a valid csrf token should success', async () => {
cookies = res.headers.get('set-cookie');
expect(cookies).toBeDefined();
res = await fetch(`${DEFAULT_ADDR}${Controller.route('csrf_test')}`, {
headers: {
'Cookie': cookies!,
}
});
expect(res.ok).toBe(true);
let csrf = await res.text();
res = await fetch(DEFAULT_ADDR, {
method: 'POST',
body: JSON.stringify({
csrf: csrf,
}),
headers: {
'Content-Type': 'application/json',
'Cookie': cookies!,
}
});
expect(res.ok).toBe(true);
});
});

91
test/_app.ts Normal file
View File

@ -0,0 +1,91 @@
import {setupMailServer, teardownMailServer} from "./_mail_server";
import Application from "../src/Application";
import Migration from "../src/db/Migration";
import {Type} from "../src/Utils";
import {MIGRATIONS} from "./_migrations";
import ExpressAppComponent from "../src/components/ExpressAppComponent";
import RedisComponent from "../src/components/RedisComponent";
import MysqlComponent from "../src/components/MysqlComponent";
import NunjucksComponent from "../src/components/NunjucksComponent";
import LogRequestsComponent from "../src/components/LogRequestsComponent";
import MailComponent from "../src/components/MailComponent";
import SessionComponent from "../src/components/SessionComponent";
import AuthComponent from "../src/auth/AuthComponent";
import AuthGuard from "../src/auth/AuthGuard";
import MagicLink from "../src/auth/models/MagicLink";
import FormHelperComponent from "../src/components/FormHelperComponent";
export default function useApp(appSupplier?: (port: number) => TestApp) {
let app: Application;
beforeAll(async (done) => {
await setupMailServer();
app = appSupplier ? appSupplier(8966) : new TestApp(8966);
await app.start();
done();
});
afterAll(async (done) => {
await app.stop();
await teardownMailServer();
done();
});
}
export class TestApp extends Application {
private readonly port: number;
constructor(port: number) {
super(require('../package.json').version, true);
this.port = port;
}
protected getMigrations(): Type<Migration>[] {
return MIGRATIONS;
}
protected async init(): Promise<void> {
this.registerComponents();
this.registerWebSocketListeners();
this.registerControllers();
}
protected registerComponents() {
const redisComponent = new RedisComponent();
const mysqlComponent = new MysqlComponent();
const expressAppComponent = new ExpressAppComponent(this.port);
this.use(expressAppComponent);
// Base
this.use(new NunjucksComponent('test/views'));
this.use(new LogRequestsComponent());
// Services
this.use(mysqlComponent);
this.use(new MailComponent());
// Session
this.use(redisComponent);
this.use(new SessionComponent(redisComponent));
// Auth
this.use(new AuthComponent(new class extends AuthGuard<MagicLink> {
public async getProofForSession(session: Express.Session): Promise<MagicLink | null> {
return await MagicLink.bySessionID(session.id, ['login', 'register']);
}
}));
// Utils
this.use(new FormHelperComponent());
}
protected registerWebSocketListeners() {
}
protected registerControllers() {
}
}
export const DEFAULT_ADDR = 'http://localhost:8966';

19
test/_mail_server.ts Normal file
View File

@ -0,0 +1,19 @@
const MailDev = require("maildev");
export const MAIL_SERVER = new MailDev({
ip: 'localhost',
});
export async function setupMailServer() {
await new Promise((resolve, reject) => MAIL_SERVER.listen((err: Error) => {
if (err) reject(err);
else resolve();
}));
};
export async function teardownMailServer() {
await new Promise((resolve, reject) => MAIL_SERVER.close((err: Error) => {
if (err) reject(err);
else resolve();
}));
};

View File

@ -0,0 +1,2 @@
{% extends './error.njk' %}
{% import 'macros.njk' as macros %}

View File

@ -0,0 +1,2 @@
{% extends './error.njk' %}
{% import 'macros.njk' as macros %}

View File

@ -0,0 +1,2 @@
{% extends './error.njk' %}
{% import 'macros.njk' as macros %}

View File

@ -0,0 +1,2 @@
{% extends './error.njk' %}
{% import 'macros.njk' as macros %}

View File

@ -0,0 +1,2 @@
{% extends './error.njk' %}
{% import 'macros.njk' as macros %}

View File

@ -0,0 +1,2 @@
{% extends './error.njk' %}
{% import 'macros.njk' as macros %}

View File

@ -0,0 +1,2 @@
{% extends './error.njk' %}
{% import 'macros.njk' as macros %}

View File

@ -0,0 +1,36 @@
{% extends '../layouts/barebone.njk' %}
{% set title = error_code + ' - ' + error_message %}
{% block _stylesheets %}
<link rel="stylesheet" href="/css/error.css">
{% endblock %}
{% block _body %}
<div class="logo"><a href="/">{{ app.name }}</a></div>
<main class="{% block class %}{% endblock %}">
{% if flash %}
{{ macros.messages(flash) }}
{% endif %}
<div class="error-code">{{ error_code }}</div>
<div class="error-message">{{ error_message }}</div>
<div class="error-instructions">{{ error_instructions|safe }}</div>
<nav>
{% if session.previousUrl and session.previousUrl != '/' and session.previousUrl != url %}
<a href="{{ session.previousUrl }}" class="button"><i data-feather="arrow-left"></i> Go back</a>
{% endif %}
<a href="/" class="button"><i data-feather="home"></i> Go to homepage</a>
</nav>
</main>
<div class="contact">
Error ID: {{ error_id }}
<br>
If you think this isn't right, please contact us with the above error ID at
<a href="mailto:{{ app.contact_email }}">{{ app.contact_email }}</a>.
</div>
{% endblock %}

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<link rel="shortcut icon" type="image/png" href="/img/logox1024.png">
<link rel="shortcut icon" type="image/png" href="/img/logox128.png">
<link rel="shortcut icon" type="image/svg" href="/img/logo.svg">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% if description %}
<meta name="description" content="{{ description }}">
{% endif %}
{% if refresh_after %}
<meta http-equiv="refresh" content="{{ refresh_after }}">
{% endif %}
{% block _stylesheets %}{% endblock %}
{% block _scripts %}
<script src="/js/app.js" defer></script>
{% endblock %}
</head>
<body>
<header>
{% block header %}{% endblock %}
</header>
{% block _body %}{% endblock %}
<footer>{% block footer %}{% endblock %}</footer>
</body>
</html>

View File

@ -0,0 +1,51 @@
{% extends './barebone.njk' %}
{% block _stylesheets %}
{{ super() }}
<link rel="stylesheet" href="/css/app.css">
{% block stylesheets %}{% endblock %}
{% endblock %}
{% block _scripts %}
{{ super() }}
{% block scripts %}{% endblock %}
{% endblock %}
{% block header %}
<a href="/" class="logo"><img src="/img/logo.svg" alt="Logo"> {{ app.name }}</a>
<nav>
<button id="menu-button"><i data-feather="menu"></i></button>
<ul id="main-menu">
{% if user %}
<li class="dropdown"><a href="{{ route('widgets') }}"><i data-feather="zap"></i> <span class="tip">Widgets</span></a></li>
<div class="separator"></div>
<li><a href="{{ route('account') }}"><i data-feather="user"></i> <span class="tip">{{ user.name }} - Account</span></a></li>
{% if user.is_admin %}
<li><a href="{{ route('early-access-backend') }}"><i data-feather="sliders"></i> <span class="tip">Backend</span></a></li>
{% endif %}
<li><a href="{{ route('logout') }}"><i data-feather="log-out"></i> <span class="tip">Log out</span></a></li>
{% else %}
<li><a href="{{ route('auth') }}"><i data-feather="log-in"></i> Log in / Register</a></li>
{% endif %}
</ul>
</nav>
{% endblock %}
{% block _body %}
<div class="container">
{{ macros.messages(flash) }}
</div>
<main>
{% if h1 %}
<h1>{{ h1 }}</h1>
{% endif %}
{% if subtitle %}
<p>{{ subtitle }}</p>
{% endif %}
{% block body %}{% endblock %}
</main>
{% endblock %}
{% block footer %}{{ app.name }} v{{ app_version }} - all rights reserved.{% endblock %}

View File

@ -0,0 +1,18 @@
{% extends './barebone.njk' %}
{% block _stylesheets %}
{{ super() }}
{% block stylesheets %}{% endblock %}
{% endblock %}
{% block _scripts %}
{{ super() }}
{% block scripts %}{% endblock %}
{% endblock %}
{% block header %}{% endblock %}
{% block _body %}
{% block body %}{% endblock %}
{% endblock %}
{% block footer %}{% endblock %}

142
test/views/macros.njk Normal file
View File

@ -0,0 +1,142 @@
{% macro message(type, content, raw=false, discreet=false) %}
<div class="message{{ ' message-discreet' if discreet }}" data-type="{{ type }}">
<i class="icon"></i>
<span class="content">
{{ content|safe if raw else content }}
</span>
</div>
{% endmacro %}
{% macro messages(flash) %}
{% set flashed = flash() %}
{% set display = 0 %}
{% for type, bag in flashed %}
{% if bag|length %}
{% set display = 1 %}
{% endif %}
{% endfor %}
{% if display %}
<div class="messages">
{% for type, bag in flashed %}
{% for content in bag %}
{{ message(type, content) }}
{% endfor %}
{% endfor %}
</div>
{% endif %}
{% endmacro %}
{% macro csrf(getCSRFToken) %}
<input type="hidden" name="csrf" value="{{ getCSRFToken() }}">
{% endmacro %}
{% macro field(_locals, type, name, value, placeholder, hint, validation_attributes='', extraData='') %}
{% set validation = _locals.validation() %}
{% set validation = validation[name] if validation[name] or null %}
{% set previousFormData = _locals.previousFormData() %}
{% set value = previousFormData[name] or value or validation.value or '' %}
{% if type == 'hidden' %}
{% if validation %}
{{ message('error', validation.message) }}
{% endif %}
<input type="hidden" name="{{ name }}" value="{{ value }}">
{% else %}
<div class="form-field{{ ' inline' if type == 'checkbox' }}">
{% if type == 'duration' %}
<div class="input-group">
{% for f in extraData %}
<div class="time-input">
{% if previousFormData[name] %}
{% set v = value[f] %}
{% else %}
{% set v = (value % 60) if f == 's' else (((value - value % 60) / 60 % 60) if f == 'm' else ((value - value % 3600) / 3600 if f == 'h')) %}
{% endif %}
<input type="number" name="{{ name }}[{{ f }}]" id="field-{{ name }}-{{ f }}"
value="{{ v }}"
min="0" {{ 'max=60' if (f == 's' or f == 'm') }}
{{ validation_attributes }}>
<label for="field-{{ name }}-{{ f }}">{{ f }}</label>
</div>
{% endfor %}
</div>
{% elseif type == 'select' %}
<select name="{{ name }}" id="field-{{ name }}" {{ validation_attributes|safe }}>
{% for option in extraData %}
<option value="{{ option }}" {{ 'selected' if value == option }}>{{ option }}</option>
{% endfor %}
</select>
<i data-feather="chevron-down"></i>
{% else %}
<input type="{{ type }}" name="{{ name }}" id="field-{{ name }}"
{% if type != 'checkbox' %} value="{{ value }}" {% endif %}
{{ 'checked' if (type == 'checkbox' and value == 'on') }}
{{ validation_attributes|safe }}>
{% endif %}
<label for="field-{{ name }}{{ '-' + extraData[0] if type == 'duration' }}">{{ placeholder }}</label>
{{ fieldError(_locals, name) }}
{% if hint %}
<div class="hint"><i data-feather="info"></i> {{ hint }}</div>
{% endif %}
</div>
{% endif %}
{% endmacro %}
{% macro fieldError(_locals, name) %}
{% set validation = _locals.validation() %}
{% set validation = validation[name] if validation[name] or null %}
{% if validation %}
<div class="error"><i data-feather="x-circle"></i> {{ validation.message }}</div>
{% endif %}
{% endmacro %}
{% macro websocket(websocketUrl, listener, reconnectOnClose = 1, checkFunction = 0) %}
<script>
document.addEventListener('DOMContentLoaded', () => {
{% if checkFunction %}
if (!{{ checkFunction }}()) return;
{% endif %}
const run = () => {
const websocket = new WebSocket('{{ websocketUrl }}');
websocket.onopen = (e) => {
console.debug('Websocket connected');
};
websocket.onmessage = (e) => {
{{ listener }}(websocket, e);
};
websocket.onerror = (e) => {
console.error('Websocket error', e);
};
websocket.onclose = (e) => {
console.debug('Websocket closed', e.code, e.reason);
{% if reconnectOnClose %}
setTimeout(run, 1000);
{% endif %}
};
};
run();
});
</script>
{% endmacro %}
{% macro paginate(pagination, routeName) %}
{% if pagination.hasPrevious() or pagination.hasNext() %}
<div class="pagination">
{% if pagination.hasPrevious() %}
<a href="{{ route(routeName, {page: pagination.page - 1}) }}"><i data-feather="chevron-left"></i></a>
{% endif %}
<span>{{ pagination.page }}</span>
{% if pagination.hasNext() %}
<a href="{{ route(routeName, {page: pagination.page + 1}) }}"><i data-feather="chevron-right"></i></a>
{% endif %}
</div>
{% endif %}
{% endmacro %}

1
test/views/test/csrf.njk Normal file
View File

@ -0,0 +1 @@
{{ getCSRFToken() }}

View File

@ -0,0 +1,3 @@
{{ route('non-existing-fake-route') }}
This should never be distributed.

368
yarn.lock
View File

@ -668,6 +668,14 @@
dependencies:
"@types/node" "*"
"@types/node-fetch@^2.5.7":
version "2.5.7"
resolved "https://registry.toot.party/@types%2fnode-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==
dependencies:
"@types/node" "*"
form-data "^3.0.0"
"@types/node@*":
version "14.0.14"
resolved "https://registry.toot.party/@types%2fnode/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce"
@ -771,7 +779,7 @@ abbrev@1:
resolved "https://registry.toot.party/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
accepts@~1.3.7:
accepts@~1.3.4, accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.toot.party/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
@ -802,6 +810,16 @@ acorn@^7.1.0:
resolved "https://registry.toot.party/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd"
integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==
addressparser@^1.0.1:
version "1.0.1"
resolved "https://registry.toot.party/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746"
integrity sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=
after@0.8.2:
version "0.8.2"
resolved "https://registry.toot.party/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
ajv@^6.5.5:
version "6.12.2"
resolved "https://registry.toot.party/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
@ -934,6 +952,11 @@ array-unique@^0.3.2:
resolved "https://registry.toot.party/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.toot.party/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
asap@^2.0.3:
version "2.0.6"
resolved "https://registry.toot.party/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
@ -961,6 +984,11 @@ astral-regex@^1.0.0:
resolved "https://registry.toot.party/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.toot.party/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
async@^2.1.1:
version "2.6.3"
resolved "https://registry.toot.party/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
@ -1060,11 +1088,31 @@ babel-runtime@^6.26.0:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.toot.party/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.toot.party/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base32.js@0.1.0:
version "0.1.0"
resolved "https://registry.toot.party/base32.js/-/base32.js-0.1.0.tgz#b582dec693c2f11e893cf064ee6ac5b6131a2202"
integrity sha1-tYLexpPC8R6JPPBk7mrFthMaIgI=
base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "https://registry.toot.party/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
base64id@1.0.0:
version "1.0.0"
resolved "https://registry.toot.party/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=
base@^0.11.1:
version "0.11.2"
resolved "https://registry.toot.party/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
@ -1085,6 +1133,13 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
better-assert@~1.0.0:
version "1.0.2"
resolved "https://registry.toot.party/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
dependencies:
callsite "1.0.0"
bignumber.js@9.0.0:
version "9.0.0"
resolved "https://registry.toot.party/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075"
@ -1095,6 +1150,11 @@ binary-extensions@^2.0.0:
resolved "https://registry.toot.party/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
blob@0.0.5:
version "0.0.5"
resolved "https://registry.toot.party/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
body-parser@1.19.0:
version "1.19.0"
resolved "https://registry.toot.party/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
@ -1203,6 +1263,11 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.toot.party/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.toot.party/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@ -1384,7 +1449,7 @@ colors@^1.1.2:
resolved "https://registry.toot.party/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
combined-stream@^1.0.6, combined-stream@~1.0.6:
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.toot.party/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@ -1396,7 +1461,7 @@ commander@2.17.x:
resolved "https://registry.toot.party/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^2.11.0, commander@^2.15.1, commander@^2.19.0:
commander@^2.11.0, commander@^2.15.1, commander@^2.19.0, commander@^2.20.0:
version "2.20.3"
resolved "https://registry.toot.party/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -1411,11 +1476,26 @@ commander@~2.19.0:
resolved "https://registry.toot.party/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
component-bind@1.0.0:
version "1.0.0"
resolved "https://registry.toot.party/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=
component-emitter@1.2.1:
version "1.2.1"
resolved "https://registry.toot.party/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
component-emitter@^1.2.1:
version "1.3.0"
resolved "https://registry.toot.party/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
component-inherit@0.0.3:
version "0.0.3"
resolved "https://registry.toot.party/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.toot.party/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -1483,6 +1563,11 @@ cookie-signature@1.0.6:
resolved "https://registry.toot.party/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
cookie@0.3.1:
version "0.3.1"
resolved "https://registry.toot.party/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.toot.party/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
@ -1508,6 +1593,14 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
resolved "https://registry.toot.party/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
cors@^2.8.5:
version "2.8.5"
resolved "https://registry.toot.party/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
dependencies:
object-assign "^4"
vary "^1"
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.toot.party/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@ -1598,13 +1691,20 @@ debug@^3.2.6:
dependencies:
ms "^2.1.1"
debug@^4.1.0, debug@^4.1.1:
debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
version "4.1.1"
resolved "https://registry.toot.party/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.toot.party/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.toot.party/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@ -1819,6 +1919,46 @@ end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
engine.io-client@~3.3.1:
version "3.3.2"
resolved "https://registry.toot.party/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa"
integrity sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==
dependencies:
component-emitter "1.2.1"
component-inherit "0.0.3"
debug "~3.1.0"
engine.io-parser "~2.1.1"
has-cors "1.1.0"
indexof "0.0.1"
parseqs "0.0.5"
parseuri "0.0.5"
ws "~6.1.0"
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2"
engine.io-parser@~2.1.0, engine.io-parser@~2.1.1:
version "2.1.3"
resolved "https://registry.toot.party/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6"
integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==
dependencies:
after "0.8.2"
arraybuffer.slice "~0.0.7"
base64-arraybuffer "0.1.5"
blob "0.0.5"
has-binary2 "~1.0.2"
engine.io@~3.3.1:
version "3.3.2"
resolved "https://registry.toot.party/engine.io/-/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59"
integrity sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==
dependencies:
accepts "~1.3.4"
base64id "1.0.0"
cookie "0.3.1"
debug "~3.1.0"
engine.io-parser "~2.1.0"
ws "~6.1.0"
entities@^1.1.1, entities@~1.1.1:
version "1.1.2"
resolved "https://registry.toot.party/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
@ -1841,7 +1981,7 @@ escape-html@~1.0.3:
resolved "https://registry.toot.party/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
escape-string-regexp@^1.0.5:
escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5:
version "1.0.5"
resolved "https://registry.toot.party/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
@ -2007,7 +2147,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extend@~3.0.2:
extend@~3.0.0, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.toot.party/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
@ -2120,6 +2260,15 @@ forever-agent@~0.6.1:
resolved "https://registry.toot.party/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@^3.0.0:
version "3.0.0"
resolved "https://registry.toot.party/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.toot.party/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@ -2283,6 +2432,18 @@ har-validator@~5.1.3:
ajv "^6.5.5"
har-schema "^2.0.0"
has-binary2@~1.0.2:
version "1.0.3"
resolved "https://registry.toot.party/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==
dependencies:
isarray "2.0.1"
has-cors@1.1.0:
version "1.1.0"
resolved "https://registry.toot.party/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.toot.party/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@ -2422,7 +2583,7 @@ human-signals@^1.1.1:
resolved "https://registry.toot.party/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.4:
iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.4, iconv-lite@~0.4.24:
version "0.4.24"
resolved "https://registry.toot.party/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@ -2454,6 +2615,11 @@ imurmurhash@^0.1.4:
resolved "https://registry.toot.party/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
indexof@0.0.1:
version "0.0.1"
resolved "https://registry.toot.party/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.toot.party/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -2496,6 +2662,11 @@ ipaddr.js@1.9.1:
resolved "https://registry.toot.party/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
ipv6-normalize@1.0.1:
version "1.0.1"
resolved "https://registry.toot.party/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz#1b3258290d365fa83239e89907dde4592e7620a8"
integrity sha1-GzJYKQ02X6gyOeiZB93kWS52IKg=
is-accessor-descriptor@^0.1.6:
version "0.1.6"
resolved "https://registry.toot.party/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
@ -2656,6 +2827,11 @@ is-windows@^1.0.2:
resolved "https://registry.toot.party/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
is-wsl@^1.1.0:
version "1.1.0"
resolved "https://registry.toot.party/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
is-wsl@^2.1.1:
version "2.2.0"
resolved "https://registry.toot.party/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
@ -2668,6 +2844,11 @@ isarray@1.0.0, isarray@~1.0.0:
resolved "https://registry.toot.party/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isarray@2.0.1:
version "2.0.1"
resolved "https://registry.toot.party/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.toot.party/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@ -3390,6 +3571,33 @@ lru-cache@^4.1.5:
pseudomap "^1.0.2"
yallist "^2.1.2"
maildev@^1.1.0:
version "1.1.0"
resolved "https://registry.toot.party/maildev/-/maildev-1.1.0.tgz#8b6977f244373be00112c942ae15dd32f5c225c9"
integrity sha512-D7mrEM/i4c5AX72aRBN9mO5snsGhEs7MvNFWmrSsRL94sIH0/zVQ1GE+ysN9J7lFMLkXNy2xPG3SGP2cjPrCRw==
dependencies:
async "^3.1.0"
commander "^2.20.0"
cors "^2.8.5"
express "^4.17.1"
mailparser-mit "^1.0.0"
opn "^6.0.0"
rimraf "^2.6.3"
smtp-connection "4.0.2"
smtp-server "3.5.0"
socket.io "2.2.0"
wildstring "1.0.9"
mailparser-mit@^1.0.0:
version "1.0.0"
resolved "https://registry.toot.party/mailparser-mit/-/mailparser-mit-1.0.0.tgz#19df8436c2a02e1d34a03ec518a2eb065e0a94a4"
integrity sha512-sckRITNb3VCT1sQ275g47MAN786pQ5lU20bLY5f794dF/ARGzuVATQ64gO13FOw8jayjFT10e5ttsripKGGXcw==
dependencies:
addressparser "^1.0.1"
iconv-lite "~0.4.24"
mime "^1.6.0"
uue "^3.1.0"
make-dir@^3.0.0:
version "3.1.0"
resolved "https://registry.toot.party/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@ -3485,7 +3693,7 @@ mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
dependencies:
mime-db "1.44.0"
mime@1.6.0:
mime@1.6.0, mime@^1.6.0:
version "1.6.0"
resolved "https://registry.toot.party/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
@ -3979,6 +4187,11 @@ node-addon-api@^2.0.0:
resolved "https://registry.toot.party/node-addon-api/-/node-addon-api-2.0.1.tgz#4fd0931bf6d7e48b219ff3e6abc73cbb0252b7a3"
integrity sha512-2WVfwRfIr1AVn3dRq4yRc2Hn35ND+mPJH6inC6bjpYCZVrpXPB4j3T6i//OGVfqVsR1t/X/axRulDsheq4F0LQ==
node-fetch@^2.6.0:
version "2.6.0"
resolved "https://registry.toot.party/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.toot.party/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@ -4016,6 +4229,16 @@ node-pre-gyp@^0.14.0:
semver "^5.3.0"
tar "^4.4.2"
nodemailer@5.0.0:
version "5.0.0"
resolved "https://registry.toot.party/nodemailer/-/nodemailer-5.0.0.tgz#bcb409eca613114e85de42646d0ce7f1fa70b716"
integrity sha512-XI4PI5L7GYcJyHkPcHlvPyRrYohNYBNRNbt1tU8PXNU3E1ADJC84a13V0vbL9AM431OP+ETacaGXAF8fGn1JvA==
nodemailer@^3.1.1:
version "3.1.8"
resolved "https://registry.toot.party/nodemailer/-/nodemailer-3.1.8.tgz#febfaccb4bd273678473a309c6cb4b4a2f3c48e3"
integrity sha1-/r+sy0vSc2eEc6MJxstLSi88SOM=
nodemailer@^6.4.6:
version "6.4.10"
resolved "https://registry.toot.party/nodemailer/-/nodemailer-6.4.10.tgz#f4c8dc7991c57f41fd081bef224ef01f7065143d"
@ -4129,11 +4352,16 @@ oauth-sign@~0.9.0:
resolved "https://registry.toot.party/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
object-assign@^4.1.0:
object-assign@^4, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.toot.party/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-component@0.0.3:
version "0.0.3"
resolved "https://registry.toot.party/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.toot.party/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@ -4183,6 +4411,13 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
opn@^6.0.0:
version "6.0.0"
resolved "https://registry.toot.party/opn/-/opn-6.0.0.tgz#3c5b0db676d5f97da1233d1ed42d182bc5a27d2d"
integrity sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==
dependencies:
is-wsl "^1.1.0"
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.toot.party/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
@ -4276,6 +4511,20 @@ parse5@5.1.0:
resolved "https://registry.toot.party/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.toot.party/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
dependencies:
better-assert "~1.0.0"
parseuri@0.0.5:
version "0.0.5"
resolved "https://registry.toot.party/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
dependencies:
better-assert "~1.0.0"
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.toot.party/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@ -4673,7 +4922,7 @@ ret@~0.1.10:
resolved "https://registry.toot.party/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
rimraf@^2.5.2, rimraf@^2.6.1:
rimraf@^2.5.2, rimraf@^2.6.1, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.toot.party/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
@ -4859,6 +5108,22 @@ slick@^1.12.2:
resolved "https://registry.toot.party/slick/-/slick-1.12.2.tgz#bd048ddb74de7d1ca6915faa4a57570b3550c2d7"
integrity sha1-vQSN23TefRymkV+qSldXCzVQwtc=
smtp-connection@4.0.2:
version "4.0.2"
resolved "https://registry.toot.party/smtp-connection/-/smtp-connection-4.0.2.tgz#d9dd68d38569f3ad9265473670d09d8f3ea518db"
integrity sha1-2d1o04Vp862SZUc2cNCdjz6lGNs=
dependencies:
nodemailer "^3.1.1"
smtp-server@3.5.0:
version "3.5.0"
resolved "https://registry.toot.party/smtp-server/-/smtp-server-3.5.0.tgz#eb2e7bd52f26b4136b9dfc2c9fa0ba70e18cdc81"
integrity sha512-7FUg09H1VmqMRlUq/QdkPxn/NK8VCFw7GMU5rdWWDbS00wbLhjRBe3Lme+AamjDSmVoP6e/WqFqsa7jVI+69pg==
dependencies:
base32.js "0.1.0"
ipv6-normalize "1.0.1"
nodemailer "5.0.0"
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.toot.party/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@ -4889,6 +5154,52 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
socket.io-adapter@~1.1.0:
version "1.1.2"
resolved "https://registry.toot.party/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
socket.io-client@2.2.0:
version "2.2.0"
resolved "https://registry.toot.party/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7"
integrity sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==
dependencies:
backo2 "1.0.2"
base64-arraybuffer "0.1.5"
component-bind "1.0.0"
component-emitter "1.2.1"
debug "~3.1.0"
engine.io-client "~3.3.1"
has-binary2 "~1.0.2"
has-cors "1.1.0"
indexof "0.0.1"
object-component "0.0.3"
parseqs "0.0.5"
parseuri "0.0.5"
socket.io-parser "~3.3.0"
to-array "0.1.4"
socket.io-parser@~3.3.0:
version "3.3.0"
resolved "https://registry.toot.party/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
dependencies:
component-emitter "1.2.1"
debug "~3.1.0"
isarray "2.0.1"
socket.io@2.2.0:
version "2.2.0"
resolved "https://registry.toot.party/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b"
integrity sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==
dependencies:
debug "~4.1.0"
engine.io "~3.3.1"
has-binary2 "~1.0.2"
socket.io-adapter "~1.1.0"
socket.io-client "2.2.0"
socket.io-parser "~3.3.0"
source-map-resolve@^0.5.0:
version "0.5.3"
resolved "https://registry.toot.party/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
@ -5186,6 +5497,11 @@ tmpl@1.0.x:
resolved "https://registry.toot.party/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
to-array@0.1.4:
version "0.1.4"
resolved "https://registry.toot.party/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA=
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.toot.party/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@ -5408,6 +5724,14 @@ utils-merge@1.0.1:
resolved "https://registry.toot.party/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
uue@^3.1.0:
version "3.1.2"
resolved "https://registry.toot.party/uue/-/uue-3.1.2.tgz#e99368414e87200012eb37de4dbaebaa1c742ad2"
integrity sha512-axKLXVqwtdI/czrjG0X8hyV1KLgeWx8F4KvSbvVCnS+RUvsQMGRjx0kfuZDXXqj0LYvVJmx3B9kWlKtEdRrJLg==
dependencies:
escape-string-regexp "~1.0.5"
extend "~3.0.0"
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.toot.party/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
@ -5440,7 +5764,7 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
vary@~1.1.2:
vary@^1, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.toot.party/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
@ -5551,6 +5875,11 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.2 || 2"
wildstring@1.0.9:
version "1.0.9"
resolved "https://registry.toot.party/wildstring/-/wildstring-1.0.9.tgz#82a696d5653c7d4ec9ba716859b6b53aba2761c5"
integrity sha1-gqaW1WU8fU7JunFoWba1OronYcU=
word-wrap@~1.2.3:
version "1.2.3"
resolved "https://registry.toot.party/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
@ -5594,6 +5923,13 @@ ws@^7.0.0, ws@^7.2.3:
resolved "https://registry.toot.party/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd"
integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==
ws@~6.1.0:
version "6.1.4"
resolved "https://registry.toot.party/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
dependencies:
async-limiter "~1.0.0"
xml-name-validator@^3.0.0:
version "3.0.0"
resolved "https://registry.toot.party/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
@ -5604,6 +5940,11 @@ xmlchars@^2.1.1:
resolved "https://registry.toot.party/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.toot.party/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.toot.party/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
@ -5681,6 +6022,11 @@ yauzl@^2.9.2:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.toot.party/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
yn@3.1.1:
version "3.1.1"
resolved "https://registry.toot.party/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"