Merge branch 'develop'
This commit is contained in:
commit
1daafa595f
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
node_modules
|
||||
.idea
|
||||
public
|
||||
dist
|
||||
dist
|
||||
yarn-error.log
|
||||
|
@ -1,6 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const createEmailAddress = document.getElementById('field-create_email');
|
||||
const username = document.getElementById('field-username');
|
||||
const email_username = document.getElementById('email_username');
|
||||
const domain = document.getElementById('field-domain');
|
||||
const recovery_email = document.getElementById('field-recovery_email');
|
||||
const recovery_email_label = recovery_email.parentElement.querySelector('.hint');
|
||||
@ -9,14 +10,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (createEmailAddress.checked) {
|
||||
recovery_email.removeAttribute('required');
|
||||
recovery_email_label.style.display = 'block';
|
||||
username.disabled = domain.disabled = false;
|
||||
domain.disabled = false;
|
||||
} else {
|
||||
recovery_email.setAttribute('required', 'required');
|
||||
recovery_email_label.style.display = 'none';
|
||||
username.disabled = domain.disabled = true;
|
||||
domain.disabled = true;
|
||||
}
|
||||
username.value = username.value.toLowerCase();
|
||||
email_username.innerText = username.value + '@';
|
||||
}
|
||||
|
||||
createEmailAddress.addEventListener('change', updateForm);
|
||||
username.addEventListener('change', updateForm);
|
||||
username.addEventListener('keyup', updateForm);
|
||||
updateForm();
|
||||
});
|
@ -11,5 +11,6 @@ export default Object.assign(require("wms-core/config/default").default, {
|
||||
host: "127.0.0.1",
|
||||
port: 6379,
|
||||
prefix: 'aldap'
|
||||
}
|
||||
},
|
||||
'prelaunch-password': '$argon2i$v=19$m=4096,t=3,p=1$V7njt+IBmIQ/epc7tuQcfA$ypJCNauYSPrjOhtb5UqTbRlqCHkEGikBApOrYmbdYC0',
|
||||
});
|
@ -1,2 +1,3 @@
|
||||
export default Object.assign(require("wms-core/config/production").default, {
|
||||
'prelaunch-password': 'CHANGE ME',
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "aldap",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"description": "Authentication LDAP server",
|
||||
"repository": "git@gitlab.com:ArisuOngaku/aldap.git",
|
||||
"author": "Alice Gaudon <alice@gaudon.pro>",
|
||||
@ -20,6 +20,7 @@
|
||||
"@types/config": "^0.0.36",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/ldapjs": "^1.0.7",
|
||||
"@types/node": "^13.13.2",
|
||||
"babel-loader": "^8.1.0",
|
||||
"concurrently": "^5.1.0",
|
||||
@ -47,6 +48,7 @@
|
||||
"dependencies": {
|
||||
"argon2": "^0.26.2",
|
||||
"config": "^3.3.1",
|
||||
"express": "^4.17.1"
|
||||
"express": "^4.17.1",
|
||||
"ldapjs": "^1.0.2"
|
||||
}
|
||||
}
|
||||
|
12
src/Aldap.ts
12
src/Aldap.ts
@ -20,6 +20,8 @@ import AuthComponent from "wms-core/auth/AuthComponent";
|
||||
import AuthGuard from "wms-core/auth/AuthGuard";
|
||||
import {PasswordAuthProof} from "./models/UserPassword";
|
||||
import {MIGRATIONS} from "./migrations";
|
||||
import LDAPServerComponent from "./LDAPServerComponent";
|
||||
import PreLaunchWall from "./controllers/PreLaunchWall";
|
||||
|
||||
export default class Aldap extends Application {
|
||||
private readonly port: number;
|
||||
@ -72,21 +74,25 @@ export default class Aldap extends Application {
|
||||
// Middlewares
|
||||
this.use(new CsrfProtectionComponent());
|
||||
|
||||
// WebSocket server
|
||||
this.use(new WebSocketServerComponent(this, expressAppComponent, redisComponent));
|
||||
|
||||
// Auth
|
||||
this.use(new AuthComponent(new class extends AuthGuard<PasswordAuthProof> {
|
||||
public async getProofForSession(session: Express.Session): Promise<any | null> {
|
||||
return PasswordAuthProof.getProofForSession(session);
|
||||
}
|
||||
}));
|
||||
|
||||
// WebSocket server
|
||||
this.use(new WebSocketServerComponent(this, expressAppComponent, redisComponent));
|
||||
|
||||
// LDAP server
|
||||
this.use(new LDAPServerComponent());
|
||||
}
|
||||
|
||||
private registerWebSocketListeners() {
|
||||
}
|
||||
|
||||
private registerControllers() {
|
||||
this.use(new PreLaunchWall());
|
||||
this.use(new HomeController());
|
||||
this.use(new AuthController());
|
||||
}
|
||||
|
74
src/LDAPServerComponent.ts
Normal file
74
src/LDAPServerComponent.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import ApplicationComponent from "wms-core/ApplicationComponent";
|
||||
import {Express, Router} from "express";
|
||||
import ldap, {InsufficientAccessRightsError, InvalidCredentialsError, Server} from "ldapjs";
|
||||
import Logger from "wms-core/Logger";
|
||||
import Username from "./models/Username";
|
||||
import UserEmail from "wms-core/auth/models/UserEmail";
|
||||
import {PasswordAuthProof} from "./models/UserPassword";
|
||||
import Throttler from "wms-core/Throttler";
|
||||
|
||||
export default class LDAPServerComponent extends ApplicationComponent<void> {
|
||||
private server?: Server;
|
||||
|
||||
public async start(app: Express, router: Router): Promise<void> {
|
||||
this.server = ldap.createServer({
|
||||
log: console
|
||||
});
|
||||
let authorize = (req: any, res: any, next: any) => {
|
||||
Logger.debug(req);
|
||||
|
||||
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
||||
return next(new InsufficientAccessRightsError());
|
||||
|
||||
return next();
|
||||
};
|
||||
this.server.bind('ou=users,dc=toot,dc=party', async (req: any, res: any, next: any) => {
|
||||
const rdns = req.dn.toString().split(', ').map((rdn: string) => rdn.split('='));
|
||||
let username;
|
||||
let email;
|
||||
for (const rdn of rdns) {
|
||||
if (rdn[0] === 'cn') {
|
||||
username = rdn[1];
|
||||
} else if (rdn[0] === 'email') {
|
||||
email = rdn[1];
|
||||
}
|
||||
}
|
||||
|
||||
Logger.debug('Matrix authentication attempt:', username, email);
|
||||
|
||||
try {
|
||||
Throttler.throttle('ldap_auth', 3, 30 * 1000, username);
|
||||
} catch (e) {
|
||||
Logger.debug('Too many auth requests');
|
||||
next(new InvalidCredentialsError());
|
||||
return;
|
||||
}
|
||||
|
||||
const user = await Username.getUserFromUsername(username);
|
||||
if (user) {
|
||||
const email = await UserEmail.getMainFromUser(user.id!);
|
||||
if (email) {
|
||||
const authProof = new PasswordAuthProof(email.email!);
|
||||
if (await authProof.authorize(req.credentials)) {
|
||||
Logger.debug('Success');
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.debug('Fail');
|
||||
next(new InvalidCredentialsError());
|
||||
});
|
||||
this.server.unbind((req: any, res: any, next: any) => {
|
||||
Logger.debug('Unbind', req);
|
||||
next();
|
||||
});
|
||||
this.server.listen(8389, '127.0.0.1', () => {
|
||||
Logger.info(`LDAP server listening on ${this.server!.url}`);
|
||||
});
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import Validator from "wms-core/db/Validator";
|
||||
import {EMAIL_REGEX} from "wms-core/db/Model";
|
||||
import {PasswordAuthProof} from "../models/UserPassword";
|
||||
import UserEmail from "wms-core/auth/models/UserEmail";
|
||||
import Username, {USERNAME_REGEXP} from "../models/Username";
|
||||
|
||||
export default class AuthController extends Controller {
|
||||
routes(): void {
|
||||
@ -33,7 +34,7 @@ export default class AuthController extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
await passwordAuthProof.authorize(req.session!, req.body.password);
|
||||
await passwordAuthProof.authorize(req.body.password, req.session);
|
||||
await req.authGuard.authenticateOrRegister(req.session!, passwordAuthProof);
|
||||
|
||||
req.flash('success', `Welcome, ${user.name}.`);
|
||||
@ -46,6 +47,7 @@ export default class AuthController extends Controller {
|
||||
|
||||
private async postRegister(req: Request, res: Response): Promise<void> {
|
||||
const validationMap: any = {
|
||||
username: new Validator().defined().between(3, 64).regexp(USERNAME_REGEXP).unique(Username),
|
||||
password: new Validator().defined().minLength(8),
|
||||
password_confirmation: new Validator().defined().sameAs('password', req.body.password),
|
||||
terms: new Validator().defined(),
|
||||
@ -53,9 +55,8 @@ export default class AuthController extends Controller {
|
||||
|
||||
let email: string;
|
||||
if (req.body.create_email) {
|
||||
validationMap['username'] = new Validator().defined().minLength(3).regexp(/^[0-9a-zA-Z_-]+$/);
|
||||
validationMap['domain'] = new Validator().defined().regexp(/^(toot\.party)$/);
|
||||
validationMap['recovery_email'] = new Validator().acceptUndefined().regexp(EMAIL_REGEX).unique(UserEmail, 'email');
|
||||
validationMap['recovery_email'] = new Validator().acceptUndefined(true).regexp(EMAIL_REGEX).unique(UserEmail, 'email');
|
||||
email = req.body.email = req.body.username + '@' + req.body.domain;
|
||||
validationMap['email'] = new Validator().defined().regexp(EMAIL_REGEX).unique(UserEmail, 'email');
|
||||
} else {
|
||||
@ -66,11 +67,18 @@ export default class AuthController extends Controller {
|
||||
|
||||
const passwordAuthProof = new PasswordAuthProof(email, false);
|
||||
const userPassword = await passwordAuthProof.register(req.body.password);
|
||||
await passwordAuthProof.authorize(req.session!, req.body.password_confirmation);
|
||||
await passwordAuthProof.authorize(req.body.password_confirmation, req.session);
|
||||
await req.authGuard.authenticateOrRegister(req.session!, passwordAuthProof, async (connection, userID) => {
|
||||
const callbacks: (() => Promise<void>)[] = [];
|
||||
|
||||
// Password
|
||||
await userPassword.setUser(userID);
|
||||
await userPassword.save(connection, c => callbacks.push(c));
|
||||
|
||||
// Username
|
||||
await new Username({user_id: userID, username: req.body.username}).save(connection, c => callbacks.push(c));
|
||||
|
||||
// Email
|
||||
if (req.body.create_email && req.body.recovery_email) {
|
||||
await new UserEmail({
|
||||
user_id: userID,
|
||||
@ -78,6 +86,7 @@ export default class AuthController extends Controller {
|
||||
main: false,
|
||||
}).save(connection, c => callbacks.push(c));
|
||||
}
|
||||
|
||||
return callbacks;
|
||||
});
|
||||
|
||||
|
50
src/controllers/PreLaunchWall.ts
Normal file
50
src/controllers/PreLaunchWall.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import Controller from "wms-core/Controller";
|
||||
import {Request, RequestHandler, Response} from "express";
|
||||
import {ForbiddenHttpError} from "wms-core/HttpError";
|
||||
import Validator from "wms-core/db/Validator";
|
||||
import argon2 from "argon2";
|
||||
import config from "config";
|
||||
|
||||
export default class PreLaunchWall extends Controller {
|
||||
public getGlobalHandlers(): RequestHandler[] {
|
||||
return [
|
||||
(req, res, next) => {
|
||||
if (!req.session) throw new ForbiddenHttpError('page', req.url);
|
||||
|
||||
if (!req.session.authorized) {
|
||||
const route = Controller.route('prelaunch-wall');
|
||||
if (req.url !== route) {
|
||||
res.redirect(route);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
routes(): void {
|
||||
this.get('/prelaunch-wall', this.getWall, 'prelaunch-wall');
|
||||
this.post('/prelaunch-wall', this.postWall, 'prelaunch-wall');
|
||||
}
|
||||
|
||||
private async getWall(req: Request, res: Response) {
|
||||
res.render('prelaunch-wall');
|
||||
}
|
||||
|
||||
private async postWall(req: Request, res: Response) {
|
||||
await this.validate({
|
||||
password: new Validator().defined(),
|
||||
}, req.body);
|
||||
|
||||
if (await argon2.verify(config.get<string>('prelaunch-password'), req.body.password)) {
|
||||
req.session!.authorized = true;
|
||||
req.flash('success', 'Authentication success!');
|
||||
res.redirect(Controller.route('home'));
|
||||
}
|
||||
|
||||
req.flash('error', 'Invalid password.');
|
||||
res.redirectBack();
|
||||
}
|
||||
}
|
@ -2,10 +2,12 @@ import CreateMigrationsTable from "wms-core/migrations/CreateMigrationsTable";
|
||||
import CreateLogsTable from "wms-core/migrations/CreateLogsTable";
|
||||
import CreateUsersAndUserEmailsTable from "wms-core/auth/migrations/CreateUsersAndUserEmailsTable";
|
||||
import CreateUserPasswordsTable from "./migrations/CreateUserPasswordsTable";
|
||||
import CreateUsernamesTable from "./migrations/CreateUsernamesTable";
|
||||
|
||||
export const MIGRATIONS = [
|
||||
CreateMigrationsTable,
|
||||
CreateLogsTable,
|
||||
CreateUsersAndUserEmailsTable,
|
||||
CreateUserPasswordsTable,
|
||||
CreateUsernamesTable,
|
||||
];
|
@ -13,5 +13,6 @@ export default class CreateUserPasswordsTable extends Migration {
|
||||
}
|
||||
|
||||
public async rollback(): Promise<void> {
|
||||
await query('DROP TABLE user_passwords');
|
||||
}
|
||||
}
|
18
src/migrations/CreateUsernamesTable.ts
Normal file
18
src/migrations/CreateUsernamesTable.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import Migration from "wms-core/db/Migration";
|
||||
import {query} from "wms-core/db/MysqlConnectionManager";
|
||||
|
||||
export default class CreateUserPasswordsTable extends Migration {
|
||||
public async install(): Promise<void> {
|
||||
await query('CREATE TABLE usernames(' +
|
||||
'id INT NOT NULL AUTO_INCREMENT,' +
|
||||
'user_id INT UNIQUE NOT NULL,' +
|
||||
'username VARCHAR(64) UNIQUE NOT NULL,' +
|
||||
'PRIMARY KEY(id),' +
|
||||
'FOREIGN KEY user_name_fk (user_id) REFERENCES users (id) ON DELETE CASCADE' +
|
||||
')');
|
||||
}
|
||||
|
||||
public async rollback(): Promise<void> {
|
||||
await query('DROP TABLE usernames');
|
||||
}
|
||||
}
|
@ -91,12 +91,14 @@ export class PasswordAuthProof implements AuthProof {
|
||||
return this.userPassword ? this.userPassword : await UserPassword.getByEmail(await this.getEmail());
|
||||
}
|
||||
|
||||
public async authorize(session: Express.Session, passwordGuess: string): Promise<boolean> {
|
||||
public async authorize(passwordGuess: string, session?: Express.Session): Promise<boolean> {
|
||||
const password = await this.getUserPassword();
|
||||
if (!password || !await password.verifyPassword(passwordGuess)) return false;
|
||||
|
||||
this.authorized = true;
|
||||
this.save(session);
|
||||
if (session) {
|
||||
this.save(session);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
32
src/models/Username.ts
Normal file
32
src/models/Username.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import Model from "wms-core/db/Model";
|
||||
import Validator from "wms-core/db/Validator";
|
||||
import User from "wms-core/auth/models/User";
|
||||
|
||||
export const USERNAME_REGEXP = /^[0-9a-z_-]+$/;
|
||||
|
||||
export default class Username extends Model {
|
||||
public static async fromUser(userID: number): Promise<Username | null> {
|
||||
const models = await this.models<Username>(this.select().where('user_id', userID));
|
||||
return models && models.length > 0 ? models[0] : null;
|
||||
}
|
||||
|
||||
public static async getUserFromUsername(username: string): Promise<User | null> {
|
||||
const models = await this.models<Username>(this.select().where('username', username.toLowerCase()));
|
||||
if (!models || models.length === 0) return null;
|
||||
return await User.getById<User>(models[0].user_id!);
|
||||
}
|
||||
|
||||
private user_id?: number;
|
||||
public username?: string;
|
||||
|
||||
|
||||
constructor(data: any) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
protected defineProperties(): void {
|
||||
this.defineProperty<number>('user_id', new Validator().defined().exists(User, 'id').unique(this));
|
||||
this.defineProperty<number>('username', new Validator().defined().between(3, 64).regexp(USERNAME_REGEXP).unique(this));
|
||||
}
|
||||
|
||||
}
|
19
views/prelaunch-wall.njk
Normal file
19
views/prelaunch-wall.njk
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends 'layouts/base.njk' %}
|
||||
|
||||
{% set title = 'ALDAP - Early access' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<div class="panel">
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<form action="{{ route('prelaunch-wall') }}" method="POST">
|
||||
{{ macros.field(_locals, 'password', 'password', null, 'Enter password') }}
|
||||
|
||||
<button type="submit">Authenticate</button>
|
||||
|
||||
{{ macros.csrf(getCSRFToken) }}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -7,21 +7,26 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Register</h1>
|
||||
|
||||
<div class="container">
|
||||
<div class="panel center">
|
||||
<h1>Register</h1>
|
||||
|
||||
<form action="{{ route('register') }}" method="POST">
|
||||
<section class="sub-panel">
|
||||
<h2>Username</h2>
|
||||
{{ macros.field(_locals, 'text', 'username', null, 'Choose your username', 'This cannot be changed later.', 'pattern="[0-9a-z_-]+" required') }}
|
||||
</section>
|
||||
|
||||
<section class="sub-panel">
|
||||
<h2>Email</h2>
|
||||
{{ macros.field(_locals, 'checkbox', 'create_email', null, 'Create an email address') }}
|
||||
|
||||
<div class="inline-fields">
|
||||
{{ macros.field(_locals, 'text', 'username', null, 'Choose your username', null, 'disabled') }}
|
||||
<span>@</span>
|
||||
<span id="email_username">@</span>
|
||||
{{ macros.field(_locals, 'select', 'domain', null, 'Choose your domain', null, 'disabled', ['toot.party']) }}
|
||||
</div>
|
||||
{{ macros.fieldError(_locals, 'email') }}
|
||||
<div class="hint"><i data-feather="info"></i> This cannot be changed later.</div>
|
||||
</section>
|
||||
|
||||
<section class="sub-panel">
|
||||
|
152
yarn.lock
152
yarn.lock
@ -1134,6 +1134,13 @@
|
||||
jest-diff "^25.2.1"
|
||||
pretty-format "^25.2.1"
|
||||
|
||||
"@types/ldapjs@^1.0.7":
|
||||
version "1.0.7"
|
||||
resolved "http://127.0.0.1:4873/@types%2fldapjs/-/ldapjs-1.0.7.tgz#e5829b8ce008098d599cfd86d403e6cafd508b76"
|
||||
integrity sha512-Cacc0pQ6fw8+J5Qwebbj2+YpYANOl09WEDjJsNyPHpNSza318mUIuAhgXDfC8kXDViymlEQIvgbvuPKovRIVEQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/mime@*":
|
||||
version "2.0.1"
|
||||
resolved "http://127.0.0.1:4873/@types%2fmime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
|
||||
@ -1628,6 +1635,11 @@ asn1.js@^4.0.0:
|
||||
inherits "^2.0.1"
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
asn1@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "http://127.0.0.1:4873/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
|
||||
integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=
|
||||
|
||||
asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "http://127.0.0.1:4873/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
@ -1635,6 +1647,11 @@ asn1@~0.2.3:
|
||||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
assert-plus@0.1.5:
|
||||
version "0.1.5"
|
||||
resolved "http://127.0.0.1:4873/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160"
|
||||
integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=
|
||||
|
||||
assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://127.0.0.1:4873/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
@ -1774,6 +1791,13 @@ babel-runtime@^6.26.0:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.11.0"
|
||||
|
||||
backoff@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "http://127.0.0.1:4873/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f"
|
||||
integrity sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=
|
||||
dependencies:
|
||||
precond "0.2"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://127.0.0.1:4873/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
@ -2125,6 +2149,16 @@ builtin-status-codes@^3.0.0:
|
||||
resolved "http://127.0.0.1:4873/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
||||
|
||||
bunyan@^1.8.3:
|
||||
version "1.8.12"
|
||||
resolved "http://127.0.0.1:4873/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797"
|
||||
integrity sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=
|
||||
optionalDependencies:
|
||||
dtrace-provider "~0.8"
|
||||
moment "^2.10.6"
|
||||
mv "~2"
|
||||
safe-json-stringify "~1"
|
||||
|
||||
bytes@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "http://127.0.0.1:4873/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||
@ -2904,7 +2938,7 @@ cyclist@^1.0.1:
|
||||
resolved "http://127.0.0.1:4873/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
|
||||
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
|
||||
|
||||
dashdash@^1.12.0:
|
||||
dashdash@^1.12.0, dashdash@^1.14.0:
|
||||
version "1.14.1"
|
||||
resolved "http://127.0.0.1:4873/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
|
||||
@ -3271,6 +3305,13 @@ download@^7.1.0:
|
||||
p-event "^2.1.0"
|
||||
pify "^3.0.0"
|
||||
|
||||
dtrace-provider@~0.8:
|
||||
version "0.8.8"
|
||||
resolved "http://127.0.0.1:4873/dtrace-provider/-/dtrace-provider-0.8.8.tgz#2996d5490c37e1347be263b423ed7b297fb0d97e"
|
||||
integrity sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
|
||||
duplexer3@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "http://127.0.0.1:4873/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||
@ -3705,6 +3746,11 @@ extglob@^2.0.4:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
extsprintf@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "http://127.0.0.1:4873/extsprintf/-/extsprintf-1.2.0.tgz#5ad946c22f5b32ba7f8cd7426711c6e8a3fc2529"
|
||||
integrity sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk=
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "http://127.0.0.1:4873/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
@ -4151,6 +4197,17 @@ glob-parent@^5.1.0, glob-parent@~5.1.0:
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^6.0.1:
|
||||
version "6.0.4"
|
||||
resolved "http://127.0.0.1:4873/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
|
||||
integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=
|
||||
dependencies:
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "2 || 3"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1:
|
||||
version "7.1.6"
|
||||
resolved "http://127.0.0.1:4873/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
@ -5698,6 +5755,30 @@ lcid@^2.0.0:
|
||||
dependencies:
|
||||
invert-kv "^2.0.0"
|
||||
|
||||
ldap-filter@0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "http://127.0.0.1:4873/ldap-filter/-/ldap-filter-0.2.2.tgz#f2b842be0b86da3352798505b31ebcae590d77d0"
|
||||
integrity sha1-8rhCvguG2jNSeYUFsx68rlkNd9A=
|
||||
dependencies:
|
||||
assert-plus "0.1.5"
|
||||
|
||||
ldapjs@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "http://127.0.0.1:4873/ldapjs/-/ldapjs-1.0.2.tgz#544ff7032b7b83c68f0701328d9297aa694340f9"
|
||||
integrity sha1-VE/3Ayt7g8aPBwEyjZKXqmlDQPk=
|
||||
dependencies:
|
||||
asn1 "0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
backoff "^2.5.0"
|
||||
bunyan "^1.8.3"
|
||||
dashdash "^1.14.0"
|
||||
ldap-filter "0.2.2"
|
||||
once "^1.4.0"
|
||||
vasync "^1.6.4"
|
||||
verror "^1.8.1"
|
||||
optionalDependencies:
|
||||
dtrace-provider "~0.8"
|
||||
|
||||
leven@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "http://127.0.0.1:4873/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
|
||||
@ -6184,7 +6265,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
|
||||
resolved "http://127.0.0.1:4873/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
|
||||
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
|
||||
|
||||
minimatch@^3.0.4, minimatch@~3.0.2:
|
||||
"minimatch@2 || 3", minimatch@^3.0.4, minimatch@~3.0.2:
|
||||
version "3.0.4"
|
||||
resolved "http://127.0.0.1:4873/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
@ -6592,6 +6673,11 @@ mkdirp@1.x, mkdirp@~1.0.3:
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
moment@^2.10.6:
|
||||
version "2.24.0"
|
||||
resolved "http://127.0.0.1:4873/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
|
||||
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
|
||||
|
||||
move-concurrently@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "http://127.0.0.1:4873/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
||||
@ -6628,6 +6714,15 @@ ms@^2.1.1:
|
||||
resolved "http://127.0.0.1:4873/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
mv@~2:
|
||||
version "2.1.1"
|
||||
resolved "http://127.0.0.1:4873/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2"
|
||||
integrity sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=
|
||||
dependencies:
|
||||
mkdirp "~0.5.1"
|
||||
ncp "~2.0.0"
|
||||
rimraf "~2.4.0"
|
||||
|
||||
mysql@^2.18.1:
|
||||
version "2.18.1"
|
||||
resolved "http://127.0.0.1:4873/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717"
|
||||
@ -6638,7 +6733,7 @@ mysql@^2.18.1:
|
||||
safe-buffer "5.1.2"
|
||||
sqlstring "2.3.1"
|
||||
|
||||
nan@^2.12.1, nan@^2.13.2:
|
||||
nan@^2.12.1, nan@^2.13.2, nan@^2.14.0:
|
||||
version "2.14.1"
|
||||
resolved "http://127.0.0.1:4873/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
|
||||
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
|
||||
@ -6665,6 +6760,11 @@ natural-compare@^1.4.0:
|
||||
resolved "http://127.0.0.1:4873/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
ncp@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "http://127.0.0.1:4873/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
|
||||
integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
|
||||
|
||||
needle@^2.2.1:
|
||||
version "2.4.1"
|
||||
resolved "http://127.0.0.1:4873/needle/-/needle-2.4.1.tgz#14af48732463d7475696f937626b1b993247a56a"
|
||||
@ -7591,6 +7691,11 @@ postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.
|
||||
source-map "^0.6.1"
|
||||
supports-color "^6.1.0"
|
||||
|
||||
precond@0.2:
|
||||
version "0.2.3"
|
||||
resolved "http://127.0.0.1:4873/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac"
|
||||
integrity sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=
|
||||
|
||||
prelude-ls@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "http://127.0.0.1:4873/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||
@ -8196,6 +8301,13 @@ rimraf@^3.0.0:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rimraf@~2.4.0:
|
||||
version "2.4.5"
|
||||
resolved "http://127.0.0.1:4873/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da"
|
||||
integrity sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=
|
||||
dependencies:
|
||||
glob "^6.0.1"
|
||||
|
||||
ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "http://127.0.0.1:4873/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
|
||||
@ -8238,6 +8350,11 @@ safe-buffer@5.2.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s
|
||||
resolved "http://127.0.0.1:4873/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
||||
|
||||
safe-json-stringify@~1:
|
||||
version "1.2.0"
|
||||
resolved "http://127.0.0.1:4873/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd"
|
||||
integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==
|
||||
|
||||
safe-regex@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "http://127.0.0.1:4873/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
|
||||
@ -9611,7 +9728,14 @@ vary@~1.1.2:
|
||||
resolved "http://127.0.0.1:4873/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|
||||
verror@1.10.0:
|
||||
vasync@^1.6.4:
|
||||
version "1.6.4"
|
||||
resolved "http://127.0.0.1:4873/vasync/-/vasync-1.6.4.tgz#dfe93616ad0e7ae801b332a9d88bfc5cdc8e1d1f"
|
||||
integrity sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8=
|
||||
dependencies:
|
||||
verror "1.6.0"
|
||||
|
||||
verror@1.10.0, verror@^1.8.1:
|
||||
version "1.10.0"
|
||||
resolved "http://127.0.0.1:4873/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
|
||||
@ -9620,6 +9744,13 @@ verror@1.10.0:
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
verror@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "http://127.0.0.1:4873/verror/-/verror-1.6.0.tgz#7d13b27b1facc2e2da90405eb5ea6e5bdd252ea5"
|
||||
integrity sha1-fROyex+swuLakEBetepuW90lLqU=
|
||||
dependencies:
|
||||
extsprintf "1.2.0"
|
||||
|
||||
vm-browserify@^1.0.1:
|
||||
version "1.1.2"
|
||||
resolved "http://127.0.0.1:4873/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
@ -9798,9 +9929,9 @@ widest-line@^3.1.0:
|
||||
string-width "^4.0.0"
|
||||
|
||||
wms-core@^0:
|
||||
version "0.4.15"
|
||||
resolved "http://127.0.0.1:4873/wms-core/-/wms-core-0.4.15.tgz#3b4ef49cbf1bcf24b52c337439c71f361665a5bf"
|
||||
integrity sha512-YoAsdJ69himgb3dT+6+aildMShFQJAD8yhQGQJNhY32RmAbl3C2z0xIhBy1kL/YAzypqZQxvBYZS14f/qd94QQ==
|
||||
version "0.4.17"
|
||||
resolved "http://127.0.0.1:4873/wms-core/-/wms-core-0.4.17.tgz#9f9d1fd93f61c81f620f96e1affd2d68b31a803f"
|
||||
integrity sha512-ybHtCDTUSXbrEme/GztBgRZCR87V7xHF7SkqJgXcxvq3RvlBomfHme72YGiCNCnMop9bmJS07QUs6kD9hEWfYw==
|
||||
dependencies:
|
||||
"@types/express" "^4.17.6"
|
||||
"@types/express-session" "^1.17.0"
|
||||
@ -9879,11 +10010,16 @@ write-file-atomic@^3.0.0:
|
||||
signal-exit "^3.0.2"
|
||||
typedarray-to-buffer "^3.1.5"
|
||||
|
||||
ws@^7.0.0, ws@^7.2.3:
|
||||
ws@^7.0.0:
|
||||
version "7.2.3"
|
||||
resolved "http://127.0.0.1:4873/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46"
|
||||
integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==
|
||||
|
||||
ws@^7.2.3:
|
||||
version "7.2.5"
|
||||
resolved "http://127.0.0.1:4873/ws/-/ws-7.2.5.tgz#abb1370d4626a5a9cd79d8de404aa18b3465d10d"
|
||||
integrity sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==
|
||||
|
||||
xdg-basedir@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "http://127.0.0.1:4873/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
|
||||
|
Loading…
Reference in New Issue
Block a user