Add MagicLinkAuthController helper class
This commit is contained in:
parent
384bd2fc17
commit
8ccf073139
@ -22,6 +22,7 @@
|
|||||||
"@types/connect-redis": "^0.0.13",
|
"@types/connect-redis": "^0.0.13",
|
||||||
"@types/cookie": "^0.3.3",
|
"@types/cookie": "^0.3.3",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
|
"@types/geoip-lite": "^1.1.31",
|
||||||
"@types/jest": "^25.2.1",
|
"@types/jest": "^25.2.1",
|
||||||
"@types/mjml": "^4.0.4",
|
"@types/mjml": "^4.0.4",
|
||||||
"@types/on-finished": "^2.3.1",
|
"@types/on-finished": "^2.3.1",
|
||||||
@ -46,6 +47,7 @@
|
|||||||
"cookie-parser": "^1.4.5",
|
"cookie-parser": "^1.4.5",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.17.1",
|
"express-session": "^1.17.1",
|
||||||
|
"geoip-lite": "^1.4.2",
|
||||||
"mjml": "^4.6.2",
|
"mjml": "^4.6.2",
|
||||||
"mysql": "^2.18.1",
|
"mysql": "^2.18.1",
|
||||||
"nodemailer": "^6.4.6",
|
"nodemailer": "^6.4.6",
|
||||||
|
156
src/auth/magic_link/MagicLinkAuthController.ts
Normal file
156
src/auth/magic_link/MagicLinkAuthController.ts
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import {Request, Response} from "express";
|
||||||
|
import Controller from "../../Controller";
|
||||||
|
import MagicLink from "../models/MagicLink";
|
||||||
|
import {REQUIRE_AUTH_MIDDLEWARE, REQUIRE_GUEST_MIDDLEWARE} from "../AuthComponent";
|
||||||
|
import {BadRequestError} from "../../HttpError";
|
||||||
|
import UserEmail from "../models/UserEmail";
|
||||||
|
import MagicLinkController from "./MagicLinkController";
|
||||||
|
import {MailTemplate} from "../../Mail";
|
||||||
|
import {AuthError} from "../AuthGuard";
|
||||||
|
import geoip from "geoip-lite";
|
||||||
|
|
||||||
|
|
||||||
|
export default abstract class AuthController extends Controller {
|
||||||
|
public static async checkAndAuth(req: Request, magicLink: MagicLink): Promise<void> {
|
||||||
|
if (magicLink.getSessionID() !== req.sessionID!) throw new BadOwnerMagicLink();
|
||||||
|
if (!await magicLink.isAuthorized()) throw new UnauthorizedMagicLink();
|
||||||
|
if (!await magicLink.isValid()) throw new InvalidMagicLink();
|
||||||
|
|
||||||
|
// Auth
|
||||||
|
await req.authGuard.authenticateOrRegister(req.session!, magicLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly loginMagicLinkActionType: string = 'Login';
|
||||||
|
protected readonly registerMagicLinkActionType: string = 'Register';
|
||||||
|
private readonly magicLinkMailTemplate: MailTemplate;
|
||||||
|
|
||||||
|
protected constructor(magicLinkMailTemplate: MailTemplate) {
|
||||||
|
super();
|
||||||
|
this.magicLinkMailTemplate = magicLinkMailTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public getRoutesPrefix(): string {
|
||||||
|
return '/auth';
|
||||||
|
}
|
||||||
|
|
||||||
|
routes(): void {
|
||||||
|
this.get('/', this.getAuth, 'auth', REQUIRE_GUEST_MIDDLEWARE);
|
||||||
|
this.post('/', this.postAuth, 'auth', REQUIRE_GUEST_MIDDLEWARE);
|
||||||
|
this.get('/check', this.getCheckAuth, 'check_auth');
|
||||||
|
this.get('/logout', this.getLogout, 'logout', REQUIRE_AUTH_MIDDLEWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async getAuth(request: Request, response: Response): Promise<void> {
|
||||||
|
const registerEmail = request.flash('register_confirm_email');
|
||||||
|
|
||||||
|
const link = await MagicLink.bySessionID(request.sessionID!, [this.loginMagicLinkActionType, this.registerMagicLinkActionType]);
|
||||||
|
if (link && await link.isValid()) {
|
||||||
|
response.redirect(Controller.route('magic_link_lobby'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.render('auth', {
|
||||||
|
register_confirm_email: registerEmail.length > 0 ? registerEmail[0] : null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async postAuth(req: Request, res: Response): Promise<void> {
|
||||||
|
const email = req.body.email;
|
||||||
|
if (!email) throw new BadRequestError('Email not specified.', 'Please try again.', req.originalUrl);
|
||||||
|
|
||||||
|
let userEmail = await UserEmail.fromEmail(email);
|
||||||
|
let isRegistration = false;
|
||||||
|
|
||||||
|
if (!userEmail) {
|
||||||
|
isRegistration = true;
|
||||||
|
userEmail = new UserEmail({
|
||||||
|
email: email,
|
||||||
|
main: true,
|
||||||
|
});
|
||||||
|
await userEmail.validate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRegistration || req.body.confirm_register === 'confirm') {
|
||||||
|
// Register (email link)
|
||||||
|
const geo = geoip.lookup(req.ip);
|
||||||
|
await MagicLinkController.sendMagicLink(
|
||||||
|
req.sessionID!,
|
||||||
|
isRegistration ? this.registerMagicLinkActionType : this.loginMagicLinkActionType,
|
||||||
|
Controller.route('auth'),
|
||||||
|
email,
|
||||||
|
this.magicLinkMailTemplate,
|
||||||
|
{
|
||||||
|
type: isRegistration ? 'register' : 'login',
|
||||||
|
ip: req.ip,
|
||||||
|
geo: geo ? `${geo.city}, ${geo.country}` : 'Unknown location',
|
||||||
|
},
|
||||||
|
req,
|
||||||
|
res
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Confirm registration req
|
||||||
|
req.flash('register_confirm_email', email);
|
||||||
|
res.redirect(Controller.route('auth'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a magic link is authorized, and authenticate if yes
|
||||||
|
*/
|
||||||
|
protected async getCheckAuth(req: Request, res: Response): Promise<void> {
|
||||||
|
const magicLink = await MagicLink.bySessionID(req.sessionID!, [this.loginMagicLinkActionType, this.registerMagicLinkActionType]);
|
||||||
|
|
||||||
|
if (!magicLink) {
|
||||||
|
res.format({
|
||||||
|
json: () => {
|
||||||
|
throw new BadRequestError('No magic link were found linked with that session.', 'Please retry once you have requested a magic link.', req.originalUrl);
|
||||||
|
},
|
||||||
|
default: () => {
|
||||||
|
req.flash('warning', 'No magic link found. Please try again.');
|
||||||
|
res.redirect(Controller.route('auth'));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await AuthController.checkAndAuth(req, magicLink);
|
||||||
|
|
||||||
|
// Auth success
|
||||||
|
const username = req.models.user?.name;
|
||||||
|
res.format({
|
||||||
|
json: () => {
|
||||||
|
res.json({'status': 'success', 'message': `Welcome, ${username}!`});
|
||||||
|
},
|
||||||
|
default: () => {
|
||||||
|
req.flash('success', `Authentication success. Welcome, ${username}!`);
|
||||||
|
res.redirect('/');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async getLogout(req: Request, res: Response): Promise<void> {
|
||||||
|
await req.authGuard.logout(req.session!);
|
||||||
|
req.flash('success', 'Successfully logged out.');
|
||||||
|
res.redirectBack('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BadOwnerMagicLink extends AuthError {
|
||||||
|
constructor() {
|
||||||
|
super(`This magic link doesn't belong to this session.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UnauthorizedMagicLink extends AuthError {
|
||||||
|
constructor() {
|
||||||
|
super(`This magic link is unauthorized.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InvalidMagicLink extends AuthError {
|
||||||
|
constructor() {
|
||||||
|
super(`This magic link is invalid.`);
|
||||||
|
}
|
||||||
|
}
|
85
yarn.lock
85
yarn.lock
@ -575,6 +575,11 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/serve-static" "*"
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
|
"@types/geoip-lite@^1.1.31":
|
||||||
|
version "1.1.31"
|
||||||
|
resolved "https://registry.toot.party/@types%2fgeoip-lite/-/geoip-lite-1.1.31.tgz#0063e47916ea982fa913a8c825f429e66b59ad10"
|
||||||
|
integrity sha512-fUfJw0jak7dvicCe+Dg5fOdXxrD89yZn8ir8TgMSOiLDx2DxwlrRZaHqB9lH617B5OR5ikI08LCQrNHHkACJvw==
|
||||||
|
|
||||||
"@types/graceful-fs@^4.1.2":
|
"@types/graceful-fs@^4.1.2":
|
||||||
version "4.1.3"
|
version "4.1.3"
|
||||||
resolved "https://registry.toot.party/@types%2fgraceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f"
|
resolved "https://registry.toot.party/@types%2fgraceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f"
|
||||||
@ -927,6 +932,13 @@ astral-regex@^1.0.0:
|
|||||||
resolved "https://registry.toot.party/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
|
resolved "https://registry.toot.party/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
|
||||||
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
|
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
|
||||||
|
|
||||||
|
async@^2.1.1:
|
||||||
|
version "2.6.3"
|
||||||
|
resolved "https://registry.toot.party/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
|
||||||
|
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.17.14"
|
||||||
|
|
||||||
async@^3.1.0:
|
async@^3.1.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.toot.party/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
|
resolved "https://registry.toot.party/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
|
||||||
@ -1131,6 +1143,11 @@ bser@2.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
node-int64 "^0.4.0"
|
node-int64 "^0.4.0"
|
||||||
|
|
||||||
|
buffer-crc32@~0.2.3:
|
||||||
|
version "0.2.13"
|
||||||
|
resolved "https://registry.toot.party/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||||
|
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||||
|
|
||||||
buffer-from@1.x, buffer-from@^1.0.0:
|
buffer-from@1.x, buffer-from@^1.0.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.toot.party/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
resolved "https://registry.toot.party/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||||
@ -1332,6 +1349,11 @@ color-name@~1.1.4:
|
|||||||
resolved "https://registry.toot.party/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
resolved "https://registry.toot.party/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
|
colors@^1.1.2:
|
||||||
|
version "1.4.0"
|
||||||
|
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.6:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.toot.party/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
resolved "https://registry.toot.party/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
@ -2006,6 +2028,13 @@ fb-watchman@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bser "2.1.1"
|
bser "2.1.1"
|
||||||
|
|
||||||
|
fd-slicer@~1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.toot.party/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
|
||||||
|
integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
|
||||||
|
dependencies:
|
||||||
|
pend "~1.2.0"
|
||||||
|
|
||||||
fill-range@^4.0.0:
|
fill-range@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.toot.party/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
|
resolved "https://registry.toot.party/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
|
||||||
@ -2123,6 +2152,19 @@ gensync@^1.0.0-beta.1:
|
|||||||
resolved "https://registry.toot.party/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
|
resolved "https://registry.toot.party/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
|
||||||
integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
|
integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
|
||||||
|
|
||||||
|
geoip-lite@^1.4.2:
|
||||||
|
version "1.4.2"
|
||||||
|
resolved "https://registry.toot.party/geoip-lite/-/geoip-lite-1.4.2.tgz#f41dc50086cce3bc31a6d2d578cad1c37f9f17b3"
|
||||||
|
integrity sha512-1rUNqar68+ldSSlSMdpLZPAM+NRokIDzB2lpQFRHSOaDVqtmy25jTAWe0lM2GqWFeaA35RiLhF8GF0vvL+qOKA==
|
||||||
|
dependencies:
|
||||||
|
async "^2.1.1"
|
||||||
|
colors "^1.1.2"
|
||||||
|
iconv-lite "^0.4.13"
|
||||||
|
ip-address "^5.8.9"
|
||||||
|
lazy "^1.0.11"
|
||||||
|
rimraf "^2.5.2"
|
||||||
|
yauzl "^2.9.2"
|
||||||
|
|
||||||
get-caller-file@^2.0.1:
|
get-caller-file@^2.0.1:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.toot.party/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
resolved "https://registry.toot.party/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||||
@ -2340,7 +2382,7 @@ human-signals@^1.1.1:
|
|||||||
resolved "https://registry.toot.party/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
resolved "https://registry.toot.party/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||||
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
||||||
|
|
||||||
iconv-lite@0.4.24, iconv-lite@^0.4.4:
|
iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.4:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.toot.party/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://registry.toot.party/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||||
@ -2395,6 +2437,15 @@ ini@^1.3.4, ini@~1.3.0:
|
|||||||
resolved "https://registry.toot.party/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
resolved "https://registry.toot.party/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||||
|
|
||||||
|
ip-address@^5.8.9:
|
||||||
|
version "5.9.4"
|
||||||
|
resolved "https://registry.toot.party/ip-address/-/ip-address-5.9.4.tgz#4660ac261ad61bd397a860a007f7e98e4eaee386"
|
||||||
|
integrity sha512-dHkI3/YNJq4b/qQaz+c8LuarD3pY24JqZWfjB8aZx1gtpc2MDILu9L9jpZe1sHpzo/yWFweQVn+U//FhazUxmw==
|
||||||
|
dependencies:
|
||||||
|
jsbn "1.1.0"
|
||||||
|
lodash "^4.17.15"
|
||||||
|
sprintf-js "1.1.2"
|
||||||
|
|
||||||
ip-regex@^2.1.0:
|
ip-regex@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.toot.party/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
resolved "https://registry.toot.party/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
||||||
@ -3031,6 +3082,11 @@ js-yaml@^3.13.1:
|
|||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
esprima "^4.0.0"
|
esprima "^4.0.0"
|
||||||
|
|
||||||
|
jsbn@1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.toot.party/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
|
||||||
|
integrity sha1-sBMHyym2GKHtJux56RH4A8TaAEA=
|
||||||
|
|
||||||
jsbn@~0.1.0:
|
jsbn@~0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.toot.party/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
resolved "https://registry.toot.party/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||||
@ -3152,6 +3208,11 @@ kleur@^3.0.3:
|
|||||||
resolved "https://registry.toot.party/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
resolved "https://registry.toot.party/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
||||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||||
|
|
||||||
|
lazy@^1.0.11:
|
||||||
|
version "1.0.11"
|
||||||
|
resolved "https://registry.toot.party/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690"
|
||||||
|
integrity sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=
|
||||||
|
|
||||||
leven@^3.1.0:
|
leven@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.toot.party/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
|
resolved "https://registry.toot.party/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
|
||||||
@ -3260,7 +3321,7 @@ lodash.unescape@^4.0.1:
|
|||||||
resolved "https://registry.toot.party/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c"
|
resolved "https://registry.toot.party/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c"
|
||||||
integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=
|
integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=
|
||||||
|
|
||||||
lodash@^4.17.13, lodash@^4.17.15:
|
lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
|
||||||
version "4.17.15"
|
version "4.17.15"
|
||||||
resolved "https://registry.toot.party/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
resolved "https://registry.toot.party/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||||
@ -4214,6 +4275,11 @@ path-to-regexp@0.1.7:
|
|||||||
resolved "https://registry.toot.party/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
resolved "https://registry.toot.party/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||||
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||||
|
|
||||||
|
pend@~1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.toot.party/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||||
|
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||||
|
|
||||||
performance-now@^2.1.0:
|
performance-now@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.toot.party/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
resolved "https://registry.toot.party/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||||
@ -4556,7 +4622,7 @@ ret@~0.1.10:
|
|||||||
resolved "https://registry.toot.party/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
resolved "https://registry.toot.party/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||||
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
||||||
|
|
||||||
rimraf@^2.6.1:
|
rimraf@^2.5.2, rimraf@^2.6.1:
|
||||||
version "2.7.1"
|
version "2.7.1"
|
||||||
resolved "https://registry.toot.party/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
resolved "https://registry.toot.party/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
||||||
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
|
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
|
||||||
@ -4839,6 +4905,11 @@ split-string@^3.0.1, split-string@^3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
extend-shallow "^3.0.0"
|
extend-shallow "^3.0.0"
|
||||||
|
|
||||||
|
sprintf-js@1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.toot.party/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
|
||||||
|
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
|
||||||
|
|
||||||
sprintf-js@~1.0.2:
|
sprintf-js@~1.0.2:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.toot.party/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
resolved "https://registry.toot.party/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||||
@ -5547,6 +5618,14 @@ yargs@^15.3.1:
|
|||||||
y18n "^4.0.0"
|
y18n "^4.0.0"
|
||||||
yargs-parser "^18.1.1"
|
yargs-parser "^18.1.1"
|
||||||
|
|
||||||
|
yauzl@^2.9.2:
|
||||||
|
version "2.10.0"
|
||||||
|
resolved "https://registry.toot.party/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
|
||||||
|
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
|
||||||
|
dependencies:
|
||||||
|
buffer-crc32 "~0.2.3"
|
||||||
|
fd-slicer "~1.1.0"
|
||||||
|
|
||||||
yn@3.1.1:
|
yn@3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.toot.party/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
resolved "https://registry.toot.party/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
Loading…
Reference in New Issue
Block a user