mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-10-01 01:36:06 -04:00
A new command since
to affect all users who have joined a protected room since a given date.
This commit is contained in:
parent
26ae55cd24
commit
98679ca6e1
@ -20,9 +20,11 @@
|
|||||||
"@types/config": "0.0.41",
|
"@types/config": "0.0.41",
|
||||||
"@types/crypto-js": "^4.0.2",
|
"@types/crypto-js": "^4.0.2",
|
||||||
"@types/html-to-text": "^8.0.1",
|
"@types/html-to-text": "^8.0.1",
|
||||||
|
"@types/humanize-duration": "^3.27.1",
|
||||||
"@types/jsdom": "^16.2.11",
|
"@types/jsdom": "^16.2.11",
|
||||||
"@types/mocha": "^9.0.0",
|
"@types/mocha": "^9.0.0",
|
||||||
"@types/node": "^16.7.10",
|
"@types/node": "^16.7.10",
|
||||||
|
"@types/shell-quote": "^1.7.1",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"eslint": "^7.32",
|
"eslint": "^7.32",
|
||||||
"expect": "^27.0.6",
|
"expect": "^27.0.6",
|
||||||
@ -36,11 +38,13 @@
|
|||||||
"config": "^3.3.6",
|
"config": "^3.3.6",
|
||||||
"express": "^4.17",
|
"express": "^4.17",
|
||||||
"html-to-text": "^8.0.0",
|
"html-to-text": "^8.0.0",
|
||||||
|
"humanize-duration": "^3.27.1",
|
||||||
"humanize-duration-ts": "^2.1.1",
|
"humanize-duration-ts": "^2.1.1",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsdom": "^16.6.0",
|
"jsdom": "^16.6.0",
|
||||||
"matrix-bot-sdk": "^0.5.19",
|
"matrix-bot-sdk": "^0.5.19",
|
||||||
"parse-duration": "^1.0.2"
|
"parse-duration": "^1.0.2",
|
||||||
|
"shell-quote": "^1.7.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
|
@ -602,6 +602,12 @@ export class Mjolnir {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a protection by name.
|
||||||
|
*
|
||||||
|
* @return If there is a protection with this name *and* it is enabled,
|
||||||
|
* return the protection.
|
||||||
|
*/
|
||||||
public getProtection(protectionName: string): Protection | null {
|
public getProtection(protectionName: string): Protection | null {
|
||||||
return this.protections.get(protectionName) ?? null;
|
return this.protections.get(protectionName) ?? null;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ import { execShutdownRoomCommand } from "./ShutdownRoomCommand";
|
|||||||
import { execAddAliasCommand, execMoveAliasCommand, execRemoveAliasCommand, execResolveCommand } from "./AliasCommands";
|
import { execAddAliasCommand, execMoveAliasCommand, execRemoveAliasCommand, execResolveCommand } from "./AliasCommands";
|
||||||
import { execKickCommand } from "./KickCommand";
|
import { execKickCommand } from "./KickCommand";
|
||||||
import { execMakeRoomAdminCommand } from "./MakeRoomAdminCommand";
|
import { execMakeRoomAdminCommand } from "./MakeRoomAdminCommand";
|
||||||
|
import { parse as tokenize } from "shell-quote";
|
||||||
|
import { execSinceCommand } from "./SinceCommand";
|
||||||
|
|
||||||
|
|
||||||
export const COMMAND_PREFIX = "!mjolnir";
|
export const COMMAND_PREFIX = "!mjolnir";
|
||||||
@ -46,6 +48,9 @@ export async function handleCommand(roomId: string, event: { content: { body: st
|
|||||||
const cmd = event['content']['body'];
|
const cmd = event['content']['body'];
|
||||||
const parts = cmd.trim().split(' ').filter(p => p.trim().length > 0);
|
const parts = cmd.trim().split(' ').filter(p => p.trim().length > 0);
|
||||||
|
|
||||||
|
// A shell-style parser that can parse `"a b c"` (with quotes) as a single argument.
|
||||||
|
const tokens = tokenize(cmd).slice(/* "!mjolnir" "command" */ 2);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (parts.length === 1 || parts[1] === 'status') {
|
if (parts.length === 1 || parts[1] === 'status') {
|
||||||
return await execStatusCommand(roomId, event, mjolnir, parts.slice(2));
|
return await execStatusCommand(roomId, event, mjolnir, parts.slice(2));
|
||||||
@ -109,6 +114,8 @@ export async function handleCommand(roomId: string, event: { content: { body: st
|
|||||||
return await execSetPowerLevelCommand(roomId, event, mjolnir, parts);
|
return await execSetPowerLevelCommand(roomId, event, mjolnir, parts);
|
||||||
} else if (parts[1] === 'shutdown' && parts[2] === 'room' && parts.length > 3) {
|
} else if (parts[1] === 'shutdown' && parts[2] === 'room' && parts.length > 3) {
|
||||||
return await execShutdownRoomCommand(roomId, event, mjolnir, parts);
|
return await execShutdownRoomCommand(roomId, event, mjolnir, parts);
|
||||||
|
} else if (parts[1] === 'since') {
|
||||||
|
return await execSinceCommand(roomId, event, mjolnir, tokens);
|
||||||
} else if (parts[1] === 'kick' && parts.length > 2) {
|
} else if (parts[1] === 'kick' && parts.length > 2) {
|
||||||
return await execKickCommand(roomId, event, mjolnir, parts);
|
return await execKickCommand(roomId, event, mjolnir, parts);
|
||||||
} else if (parts[1] === 'make' && parts[2] === 'admin' && parts.length > 3) {
|
} else if (parts[1] === 'make' && parts[2] === 'admin' && parts.length > 3) {
|
||||||
@ -149,6 +156,7 @@ export async function handleCommand(roomId: string, event: { content: { body: st
|
|||||||
"!mjolnir alias add <room alias> <target room alias/ID> - Adds <room alias> to <target room>\n" +
|
"!mjolnir alias add <room alias> <target room alias/ID> - Adds <room alias> to <target room>\n" +
|
||||||
"!mjolnir alias remove <room alias> - Deletes the room alias from whatever room it is attached to\n" +
|
"!mjolnir alias remove <room alias> - Deletes the room alias from whatever room it is attached to\n" +
|
||||||
"!mjolnir resolve <room alias> - Resolves a room alias to a room ID\n" +
|
"!mjolnir resolve <room alias> - Resolves a room alias to a room ID\n" +
|
||||||
|
"!mjolnir since <date>/<duration> <action> [reason] [rooms...] - Apply an action to all users who joined a room since a given date" +
|
||||||
"!mjolnir shutdown room <room alias/ID> [message] - Uses the bot's account to shut down a room, preventing access to the room on this server\n" +
|
"!mjolnir shutdown room <room alias/ID> [message] - Uses the bot's account to shut down a room, preventing access to the room on this server\n" +
|
||||||
"!mjolnir powerlevel <user ID> <power level> [room alias/ID] - Sets the power level of the user in the specified room (or all protected rooms)\n" +
|
"!mjolnir powerlevel <user ID> <power level> [room alias/ID] - Sets the power level of the user in the specified room (or all protected rooms)\n" +
|
||||||
"!mjolnir make admin <room alias> [user alias/ID] - Make the specified user or the bot itself admin of the room\n" +
|
"!mjolnir make admin <room alias> [user alias/ID] - Make the specified user or the bot itself admin of the room\n" +
|
||||||
|
@ -18,7 +18,7 @@ import { Mjolnir } from "../Mjolnir";
|
|||||||
import { LogLevel } from "matrix-bot-sdk";
|
import { LogLevel } from "matrix-bot-sdk";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
|
||||||
// !mjolnir kick <user> [room] [reason]
|
// !mjolnir kick <user|filter> [room] [reason]
|
||||||
export async function execKickCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
export async function execKickCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
||||||
const userId = parts[2];
|
const userId = parts[2];
|
||||||
|
|
||||||
|
240
src/commands/SinceCommand.ts
Normal file
240
src/commands/SinceCommand.ts
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Mjolnir } from "../Mjolnir";
|
||||||
|
import { LogLevel, LogService, RichReply } from "matrix-bot-sdk";
|
||||||
|
import { htmlEscape, parseDuration } from "../utils";
|
||||||
|
import { ParseEntry } from "shell-quote";
|
||||||
|
import { HumanizeDurationLanguage, HumanizeDuration } from "humanize-duration-ts";
|
||||||
|
|
||||||
|
const HUMANIZE_LAG_SERVICE: HumanizeDurationLanguage = new HumanizeDurationLanguage();
|
||||||
|
const HUMANIZER: HumanizeDuration = new HumanizeDuration(HUMANIZE_LAG_SERVICE);
|
||||||
|
|
||||||
|
enum Action {
|
||||||
|
Kick = "kick",
|
||||||
|
Ban = "ban",
|
||||||
|
Show = "show"
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<T> = {ok: T} | {error: string};
|
||||||
|
|
||||||
|
function parseToken<T>(name: string, token: ParseEntry, parser: (source: string) => Result<T>): Result<T> {
|
||||||
|
if (!token) {
|
||||||
|
return { error: `Missing ${name}`};
|
||||||
|
}
|
||||||
|
if (typeof token === "object" && "pattern" in token) {
|
||||||
|
// In future versions, we *might* be smarter patterns, but not yet.
|
||||||
|
token = token.pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof token !== "string") {
|
||||||
|
return { error: `Invalid ${name}` };
|
||||||
|
}
|
||||||
|
const result = parser(token);
|
||||||
|
if ("error" in result) {
|
||||||
|
if (result.error) {
|
||||||
|
return { error: `Invalid ${name} ${htmlEscape(token)}: ${result.error}`};
|
||||||
|
} else {
|
||||||
|
return { error: `Invalid ${name} ${htmlEscape(token)}`};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTokenAsString(name: string, token: ParseEntry): {error: string}|{ok: string} {
|
||||||
|
if (!token) {
|
||||||
|
return { error: `Missing ${name}`};
|
||||||
|
}
|
||||||
|
if (typeof token === "object" && "pattern" in token) {
|
||||||
|
// In future versions, we *might* be smarter patterns, but not yet.
|
||||||
|
token = token.pattern;
|
||||||
|
}
|
||||||
|
if (typeof token === "string") {
|
||||||
|
return {ok: token};
|
||||||
|
}
|
||||||
|
return { error: `Invalid ${name}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
// !mjolnir since <date>/<duration> <action> <number> [reason] [...rooms]
|
||||||
|
export async function execSinceCommand(destinationRoomId: string, event: any, mjolnir: Mjolnir, tokens: ParseEntry[]) {
|
||||||
|
const [dateOrDurationToken, actionToken, maxEntriesToken, ...optionalTokens] = tokens;
|
||||||
|
|
||||||
|
// Parse origin date or duration.
|
||||||
|
const minDateResult = parseToken("<date>/<duration>", dateOrDurationToken, source => {
|
||||||
|
// Attempt to parse `<date>/<duration>` as a date.
|
||||||
|
let maybeMinDate = new Date(source);
|
||||||
|
let maybeMaxAgeMS = Date.now() - maybeMinDate.getTime() as number;
|
||||||
|
if (!Number.isNaN(maybeMaxAgeMS)) {
|
||||||
|
return { ok: { minDate: maybeMinDate, maxAgeMS: maybeMaxAgeMS} };
|
||||||
|
}
|
||||||
|
|
||||||
|
//...or as a duration
|
||||||
|
maybeMaxAgeMS = parseDuration(source);
|
||||||
|
if (maybeMaxAgeMS && !Number.isNaN(maybeMaxAgeMS)) {
|
||||||
|
maybeMaxAgeMS = Math.abs(maybeMaxAgeMS);
|
||||||
|
return { ok: { minDate: new Date(Date.now() - maybeMaxAgeMS), maxAgeMS: maybeMaxAgeMS } }
|
||||||
|
}
|
||||||
|
return { error: "" };
|
||||||
|
});
|
||||||
|
if ("error" in minDateResult) {
|
||||||
|
return mjolnir.logMessage(LogLevel.WARN, "SinceCommand", minDateResult.error);
|
||||||
|
}
|
||||||
|
const { minDate, maxAgeMS } = minDateResult.ok!;
|
||||||
|
|
||||||
|
// Parse max entries.
|
||||||
|
const maxEntriesResult = parseToken("<maxEntries>", maxEntriesToken, source => {
|
||||||
|
const maybeMaxEntries = Number.parseInt(source, 10);
|
||||||
|
if (Number.isNaN(maybeMaxEntries)) {
|
||||||
|
return { error: "Not a number" };
|
||||||
|
} else {
|
||||||
|
return { ok: maybeMaxEntries };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ("error" in maxEntriesResult) {
|
||||||
|
return mjolnir.logMessage(LogLevel.WARN, "SinceCommand", maxEntriesResult.error);
|
||||||
|
}
|
||||||
|
const maxEntries = maxEntriesResult.ok!;
|
||||||
|
|
||||||
|
// Attempt to parse `<action>` as Action.
|
||||||
|
const actionResult = parseToken("<action>", actionToken, source => {
|
||||||
|
for (let key in Action) {
|
||||||
|
const maybeAction = Action[key as keyof typeof Action];
|
||||||
|
if (key === source) {
|
||||||
|
return { ok: maybeAction }
|
||||||
|
} else if (maybeAction === source) {
|
||||||
|
return { ok: maybeAction }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {error: `Expected one of ${JSON.stringify(Action)}`};
|
||||||
|
})
|
||||||
|
if ("error" in actionResult) {
|
||||||
|
return mjolnir.logMessage(LogLevel.WARN, "SinceCommand", actionResult.error);
|
||||||
|
}
|
||||||
|
const action: Action = actionResult.ok!;
|
||||||
|
|
||||||
|
// Now list affected rooms.
|
||||||
|
const rooms: Set<string> = new Set();
|
||||||
|
let reason: string | undefined;
|
||||||
|
for (let i = 0; i < optionalTokens.length; ++i) {
|
||||||
|
const token = optionalTokens[i];
|
||||||
|
const maybeRoomResult = getTokenAsString("[room]", token);
|
||||||
|
if ("error" in maybeRoomResult) {
|
||||||
|
return mjolnir.logMessage(LogLevel.WARN, "SinceCommand", maybeRoomResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const maybeRoom = maybeRoomResult.ok!;
|
||||||
|
|
||||||
|
if (maybeRoom === "*") {
|
||||||
|
for (let roomId of Object.keys(mjolnir.protectedRooms)) {
|
||||||
|
rooms.add(roomId);
|
||||||
|
}
|
||||||
|
} else if (maybeRoom.startsWith("#") || maybeRoom.startsWith("!")) {
|
||||||
|
const roomId = await mjolnir.client.resolveRoom(maybeRoom);
|
||||||
|
if (!(roomId in mjolnir.protectedRooms)) {
|
||||||
|
return mjolnir.logMessage(LogLevel.WARN, "SinceCommand", `This room is not protected: ${htmlEscape(roomId)}.`);
|
||||||
|
}
|
||||||
|
rooms.add(roomId);
|
||||||
|
} else {
|
||||||
|
if (i === 0) {
|
||||||
|
// First argument may not be a room.
|
||||||
|
reason = maybeRoom;
|
||||||
|
} else {
|
||||||
|
return mjolnir.logMessage(LogLevel.WARN, "SinceCommand", `Invalid room ${htmlEscape(maybeRoom)}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rooms.size === 0) {
|
||||||
|
return mjolnir.logMessage(LogLevel.WARN, "SinceCommand", `Missing rooms. Use "*" if you wish to apply to every protected room.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const progressEventId = await mjolnir.client.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '⏳');
|
||||||
|
|
||||||
|
for (let targetRoomId of rooms) {
|
||||||
|
let {html, text} = await (async () => {
|
||||||
|
switch (action) {
|
||||||
|
case Action.Show: {
|
||||||
|
return makeJoinStatus(mjolnir, targetRoomId, maxEntries, minDate, maxAgeMS);
|
||||||
|
}
|
||||||
|
case Action.Kick: {
|
||||||
|
const joins = mjolnir.roomJoins.getUsersInRoom(targetRoomId, minDate, maxEntries);
|
||||||
|
let results = { good: 0, bad: 0};
|
||||||
|
for (let join of joins) {
|
||||||
|
try {
|
||||||
|
await mjolnir.client.kickUser(join.userId, targetRoomId, reason);
|
||||||
|
results.good += 1;
|
||||||
|
} catch (ex) {
|
||||||
|
LogService.warn("SinceCommand", "Error while attempting to kick user", ex);
|
||||||
|
results.bad += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const text_ = `Attempted to kick ${joins.length} users from room ${targetRoomId}, ${results.good} kicked, ${results.bad} failures`;
|
||||||
|
return {
|
||||||
|
html: text_,
|
||||||
|
text: text_,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Action.Ban: {
|
||||||
|
const joins = mjolnir.roomJoins.getUsersInRoom(targetRoomId, minDate, maxEntries);
|
||||||
|
|
||||||
|
let results = { good: 0, bad: 0};
|
||||||
|
for (let join of joins) {
|
||||||
|
try {
|
||||||
|
await mjolnir.client.banUser(join.userId, targetRoomId, reason);
|
||||||
|
results.good += 1;
|
||||||
|
} catch (ex) {
|
||||||
|
LogService.warn("SinceCommand", "Error while attempting to ban user", ex);
|
||||||
|
results.bad += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const text_ = `Attempted to ban ${joins.length} users from room ${targetRoomId}, ${results.good} kicked, ${results.bad} failures`;
|
||||||
|
return {
|
||||||
|
html: text_,
|
||||||
|
text: text_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
const reply = RichReply.createFor(destinationRoomId, event, text, html);
|
||||||
|
reply["msgtype"] = "m.notice";
|
||||||
|
/* no need to await */ mjolnir.client.sendMessage(destinationRoomId, reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
await mjolnir.client.redactEvent(destinationRoomId, progressEventId);
|
||||||
|
mjolnir.client.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '✅');
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeJoinStatus(mjolnir: Mjolnir, targetRoomId: string, maxEntries: number, minDate: Date, maxAgeMS: number): {html: string, text: string} {
|
||||||
|
const HUMANIZER_OPTIONS = {
|
||||||
|
// Reduce "1 day" => "1day" to simplify working with CSV.
|
||||||
|
spacer: "",
|
||||||
|
// Reduce "1 day, 2 hours" => "1.XXX day" to simplify working with CSV.
|
||||||
|
largest: 1,
|
||||||
|
};
|
||||||
|
const maxAgeHumanReadable = HUMANIZER.humanize(maxAgeMS, HUMANIZER_OPTIONS);
|
||||||
|
const joins = mjolnir.roomJoins.getUsersInRoom(targetRoomId, minDate, maxEntries);
|
||||||
|
const htmlFragments = [];
|
||||||
|
const textFragments = [];
|
||||||
|
for (let join of joins) {
|
||||||
|
const durationHumanReadable = HUMANIZER.humanize(Date.now() - join.timestamp, HUMANIZER_OPTIONS);
|
||||||
|
htmlFragments.push(`<li>${htmlEscape(join.userId)}: ${durationHumanReadable}</li>`);
|
||||||
|
textFragments.push(`- ${join.userId}: ${durationHumanReadable}`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
html: `${joins.length} recent joins (cut at ${maxAgeHumanReadable} ago / ${maxEntries} entries): <ul> ${htmlFragments.join()} </ul>`,
|
||||||
|
text: `${joins.length} recent joins (cut at ${maxAgeHumanReadable} ago / ${maxEntries} entries):\n${textFragments.join("\n")}`
|
||||||
|
}
|
||||||
|
}
|
@ -16,17 +16,9 @@ limitations under the License.
|
|||||||
|
|
||||||
import { Mjolnir, STATE_CHECKING_PERMISSIONS, STATE_NOT_STARTED, STATE_RUNNING, STATE_SYNCING } from "../Mjolnir";
|
import { Mjolnir, STATE_CHECKING_PERMISSIONS, STATE_NOT_STARTED, STATE_RUNNING, STATE_SYNCING } from "../Mjolnir";
|
||||||
import { RichReply } from "matrix-bot-sdk";
|
import { RichReply } from "matrix-bot-sdk";
|
||||||
import { htmlEscape } from "../utils";
|
import { htmlEscape, parseDuration } from "../utils";
|
||||||
import { default as parseDuration } from "parse-duration";
|
|
||||||
import { HumanizeDurationLanguage, HumanizeDuration } from "humanize-duration-ts";
|
import { HumanizeDurationLanguage, HumanizeDuration } from "humanize-duration-ts";
|
||||||
|
|
||||||
// Define a few aliases to simplify parsing durations.
|
|
||||||
|
|
||||||
parseDuration["days"] = parseDuration["day"];
|
|
||||||
parseDuration["weeks"] = parseDuration["week"] = parseDuration["wk"];
|
|
||||||
parseDuration["months"] = parseDuration["month"];
|
|
||||||
parseDuration["years"] = parseDuration["year"];
|
|
||||||
|
|
||||||
const HUMANIZE_LAG_SERVICE: HumanizeDurationLanguage = new HumanizeDurationLanguage();
|
const HUMANIZE_LAG_SERVICE: HumanizeDurationLanguage = new HumanizeDurationLanguage();
|
||||||
const HUMANIZER: HumanizeDuration = new HumanizeDuration(HUMANIZE_LAG_SERVICE);
|
const HUMANIZER: HumanizeDuration = new HumanizeDuration(HUMANIZE_LAG_SERVICE);
|
||||||
|
|
||||||
@ -36,10 +28,10 @@ export async function execStatusCommand(roomId: string, event: any, mjolnir: Mjo
|
|||||||
case undefined:
|
case undefined:
|
||||||
case 'mjolnir':
|
case 'mjolnir':
|
||||||
return showMjolnirStatus(roomId, event, mjolnir);
|
return showMjolnirStatus(roomId, event, mjolnir);
|
||||||
case 'protection':
|
|
||||||
return showProtectionStatus(roomId, event, mjolnir, parts.slice(/* ["protection"] */ 1));
|
|
||||||
case 'joins':
|
case 'joins':
|
||||||
return showJoinsStatus(roomId, event, mjolnir, parts.slice(/* ["joins"] */ 1));
|
return showJoinsStatus(roomId, event, mjolnir, parts.slice(/* ["joins"] */ 1));
|
||||||
|
case 'protection':
|
||||||
|
return showProtectionStatus(roomId, event, mjolnir, parts.slice(/* ["protection"] */ 1));
|
||||||
default:
|
default:
|
||||||
throw new Error(`Invalid status command: ${htmlEscape(parts[0])}`);
|
throw new Error(`Invalid status command: ${htmlEscape(parts[0])}`);
|
||||||
}
|
}
|
||||||
|
12
src/utils.ts
12
src/utils.ts
@ -30,6 +30,18 @@ import {
|
|||||||
import { Mjolnir } from "./Mjolnir";
|
import { Mjolnir } from "./Mjolnir";
|
||||||
import config from "./config";
|
import config from "./config";
|
||||||
import { ClientRequest, IncomingMessage } from "http";
|
import { ClientRequest, IncomingMessage } from "http";
|
||||||
|
import { default as parseDuration } from "parse-duration";
|
||||||
|
|
||||||
|
// Define a few aliases to simplify parsing durations.
|
||||||
|
|
||||||
|
parseDuration["days"] = parseDuration["day"];
|
||||||
|
parseDuration["weeks"] = parseDuration["week"] = parseDuration["wk"];
|
||||||
|
parseDuration["months"] = parseDuration["month"];
|
||||||
|
parseDuration["years"] = parseDuration["year"];
|
||||||
|
|
||||||
|
// ... and reexport it
|
||||||
|
export { parseDuration };
|
||||||
|
|
||||||
|
|
||||||
export function htmlEscape(input: string): string {
|
export function htmlEscape(input: string): string {
|
||||||
return input.replace(/["&<>]/g, (char: string) => ({
|
return input.replace(/["&<>]/g, (char: string) => ({
|
||||||
|
@ -10,7 +10,23 @@ import * as crypto from "crypto";
|
|||||||
* @param targetEventThunk A function that produces an event ID when called. This event ID is then used to listen for a reply.
|
* @param targetEventThunk A function that produces an event ID when called. This event ID is then used to listen for a reply.
|
||||||
* @returns The replying event.
|
* @returns The replying event.
|
||||||
*/
|
*/
|
||||||
export async function getFirstReply(client: MatrixClient, targetRoom: string, targetEventThunk: () => Promise<string>): Promise<any> {
|
export async function getFirstReply(client: MatrixClient, targetRoom: string, targetEventThunk: () => Promise<string>): Promise<any> {
|
||||||
|
return getNthReply(client, targetRoom, 1, targetEventThunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that resolves to the nth event replying to the event produced by targetEventThunk.
|
||||||
|
* @param client A MatrixClient that is already in the targetRoom. We will use it to listen for the event produced by targetEventThunk.
|
||||||
|
* This function assumes that the start() has already been called on the client.
|
||||||
|
* @param targetRoom The room to listen for the reply in.
|
||||||
|
* @param n The number of events to wait for. Must be >= 1.
|
||||||
|
* @param targetEventThunk A function that produces an event ID when called. This event ID is then used to listen for a reply.
|
||||||
|
* @returns The replying event.
|
||||||
|
*/
|
||||||
|
export async function getNthReply(client: MatrixClient, targetRoom: string, n: number, targetEventThunk: () => Promise<string>): Promise<any> {
|
||||||
|
if (Number.isNaN(n) || !Number.isInteger(n) || n <= 0) {
|
||||||
|
throw new TypeError(`Invalid number of events ${n}`);
|
||||||
|
}
|
||||||
let reactionEvents = [];
|
let reactionEvents = [];
|
||||||
const addEvent = function (roomId, event) {
|
const addEvent = function (roomId, event) {
|
||||||
if (roomId !== targetRoom) return;
|
if (roomId !== targetRoom) return;
|
||||||
@ -27,7 +43,10 @@ import * as crypto from "crypto";
|
|||||||
for (let event of reactionEvents) {
|
for (let event of reactionEvents) {
|
||||||
const in_reply_to = event.content['m.relates_to']?.['m.in_reply_to'];
|
const in_reply_to = event.content['m.relates_to']?.['m.in_reply_to'];
|
||||||
if (in_reply_to?.event_id === targetEventId) {
|
if (in_reply_to?.event_id === targetEventId) {
|
||||||
return event;
|
n -= 1;
|
||||||
|
if (n == 0) {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await new Promise(resolve => {
|
return await new Promise(resolve => {
|
||||||
@ -36,7 +55,10 @@ import * as crypto from "crypto";
|
|||||||
if (event.type !== 'm.room.message') return;
|
if (event.type !== 'm.room.message') return;
|
||||||
const in_reply_to = event.content['m.relates_to']?.['m.in_reply_to'];
|
const in_reply_to = event.content['m.relates_to']?.['m.in_reply_to'];
|
||||||
if (in_reply_to?.event_id === targetEventId) {
|
if (in_reply_to?.event_id === targetEventId) {
|
||||||
resolve(event)
|
n -= 1;
|
||||||
|
if (n == 0) {
|
||||||
|
resolve(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.on('room.event', targetCb);
|
client.on('room.event', targetCb);
|
||||||
@ -50,7 +72,6 @@ import * as crypto from "crypto";
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise that resolves to an event that is reacting to the event produced by targetEventThunk.
|
* Returns a promise that resolves to an event that is reacting to the event produced by targetEventThunk.
|
||||||
* @param client A MatrixClient that is already in the targetRoom that can be started to listen for the event produced by targetEventThunk.
|
* @param client A MatrixClient that is already in the targetRoom that can be started to listen for the event produced by targetEventThunk.
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { strict as assert } from "assert";
|
import { strict as assert } from "assert";
|
||||||
import { SynapseRoomProperty } from "matrix-bot-sdk";
|
import { SynapseRoomProperty } from "matrix-bot-sdk";
|
||||||
|
import { COMMAND_PREFIX } from "../../src/commands/CommandHandler";
|
||||||
|
import { execKickCommand } from "../../src/commands/KickCommand";
|
||||||
|
import { Mjolnir } from "../../src/Mjolnir";
|
||||||
import { RoomMemberManager } from "../../src/RoomMembers";
|
import { RoomMemberManager } from "../../src/RoomMembers";
|
||||||
import { newTestUser } from "./clientHelper";
|
import { newTestUser } from "./clientHelper";
|
||||||
import { getFirstReply } from "./commands/commandUtils";
|
import { getFirstReply, getNthReply } from "./commands/commandUtils";
|
||||||
|
|
||||||
describe("Test: Testing RoomMemberManager", function() {
|
describe("Test: Testing RoomMemberManager", function() {
|
||||||
it("RoomMemberManager counts correctly when we call handleEvent manually", function() {
|
it("RoomMemberManager counts correctly when we call handleEvent manually", function() {
|
||||||
@ -245,10 +248,10 @@ describe("Test: Testing RoomMemberManager", function() {
|
|||||||
|
|
||||||
afterEach(async function() {
|
afterEach(async function() {
|
||||||
await this.moderator?.stop();
|
await this.moderator?.stop();
|
||||||
if (this.users) {
|
for (let array of [this.users, this.goodUsers, this.badUsers]) {
|
||||||
for (let client of this.users) {
|
for (let client of array || []) {
|
||||||
await client.stop();
|
await client.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -374,4 +377,200 @@ describe("Test: Testing RoomMemberManager", function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it("!mjolnir since kicks the correct users", async function() {
|
||||||
|
this.timeout(600_000);
|
||||||
|
const start = new Date(Date.now() - 10_000);
|
||||||
|
|
||||||
|
// Setup a moderator.
|
||||||
|
this.moderator = await newTestUser({ name: { contains: "moderator" } });
|
||||||
|
await this.moderator.joinRoom(this.mjolnir.managementRoomId);
|
||||||
|
|
||||||
|
// Create a few users.
|
||||||
|
this.goodUsers = [];
|
||||||
|
this.badUsers = [];
|
||||||
|
const SAMPLE_SIZE = 10;
|
||||||
|
for (let i = 0; i < SAMPLE_SIZE; ++i) {
|
||||||
|
this.goodUsers.push(await newTestUser({ name: { contains: `good_user_${i}_room_member_test` } }));
|
||||||
|
this.badUsers.push(await newTestUser({ name: { contains: `bad_user_${i}_room_member_test` } }));
|
||||||
|
}
|
||||||
|
const goodUserIds = [];
|
||||||
|
const badUserIds = [];
|
||||||
|
for (let client of this.goodUsers) {
|
||||||
|
goodUserIds.push(await client.getUserId());
|
||||||
|
}
|
||||||
|
for (let client of this.badUsers) {
|
||||||
|
badUserIds.push(await client.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and protect rooms.
|
||||||
|
// - room 0 remains unprotected, as witness;
|
||||||
|
// - room 1 is protected but won't be targeted directly, also as witness.
|
||||||
|
const NUMBER_OF_ROOMS = 12;
|
||||||
|
const roomIds = [];
|
||||||
|
const mjolnirUserId = await this.mjolnir.client.getUserId();
|
||||||
|
for (let i = 0; i < NUMBER_OF_ROOMS; ++i) {
|
||||||
|
const roomId = await this.moderator.createRoom({
|
||||||
|
invite: [mjolnirUserId, ...goodUserIds, ...badUserIds],
|
||||||
|
});
|
||||||
|
roomIds.push(roomId);
|
||||||
|
}
|
||||||
|
for (let i = 1; i < roomIds.length; ++i) {
|
||||||
|
// Protect all rooms except roomIds[0], as witness.
|
||||||
|
const roomId = roomIds[i];
|
||||||
|
await this.mjolnir.client.joinRoom(roomId);
|
||||||
|
await this.moderator.setUserPowerLevel(mjolnirUserId, roomId, 100);
|
||||||
|
await this.moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir rooms add ${roomId}` });
|
||||||
|
}
|
||||||
|
|
||||||
|
let protectedRoomsUpdated = false;
|
||||||
|
do {
|
||||||
|
let protectedRooms = this.mjolnir.protectedRooms;
|
||||||
|
protectedRoomsUpdated = true;
|
||||||
|
for (let i = 1; i < roomIds.length; ++i) {
|
||||||
|
const roomId = roomIds[i];
|
||||||
|
if (!(roomId in protectedRooms)) {
|
||||||
|
protectedRoomsUpdated = false;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1_000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!protectedRoomsUpdated);
|
||||||
|
|
||||||
|
// Good users join before cut date.
|
||||||
|
for (let user of this.goodUsers) {
|
||||||
|
for (let roomId of roomIds) {
|
||||||
|
await user.joinRoom(roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 5_000));
|
||||||
|
|
||||||
|
const cutDate = new Date();
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 5_000));
|
||||||
|
|
||||||
|
// Bad users join after cut date.
|
||||||
|
for (let user of this.badUsers) {
|
||||||
|
for (let roomId of roomIds) {
|
||||||
|
await user.joinRoom(roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Method {
|
||||||
|
kick,
|
||||||
|
ban
|
||||||
|
}
|
||||||
|
const WITNESS_UNPROTECTED_ROOM_ID = roomIds[0];
|
||||||
|
const WITNESS_ROOM_ID = roomIds[1];
|
||||||
|
const EXPERIMENTS = [
|
||||||
|
// Kick bad users in one room, using duration syntax, no reason.
|
||||||
|
{
|
||||||
|
name: "kick with duration",
|
||||||
|
command: roomId => `!mjolnir since ${Date.now() - cutDate.getTime()}ms kick 100 ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.kick,
|
||||||
|
},
|
||||||
|
// Ban bad users in one room, using duration syntax, no reason.
|
||||||
|
{
|
||||||
|
name: "ban with duration",
|
||||||
|
command: roomId => `!mjolnir since ${Date.now() - cutDate.getTime()}ms ban 100 ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.ban,
|
||||||
|
},
|
||||||
|
// Kick bad users in one room, using date syntax, no reason.
|
||||||
|
{
|
||||||
|
name: "kick with date",
|
||||||
|
command: roomId => `!mjolnir since "${cutDate}" kick 100 ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.kick,
|
||||||
|
},
|
||||||
|
// Ban bad users in one room, using date syntax, no reason.
|
||||||
|
{
|
||||||
|
name: "ban with date",
|
||||||
|
command: roomId => `!mjolnir since "${cutDate}" ban 100 ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.ban,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Kick bad users in one room, using duration syntax, with reason.
|
||||||
|
{
|
||||||
|
name: "kick with duration and reason",
|
||||||
|
command: roomId => `!mjolnir since ${Date.now() - cutDate.getTime()}ms kick 100 "bad, bad user" ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.kick,
|
||||||
|
},
|
||||||
|
// Ban bad users in one room, using duration syntax, with reason.
|
||||||
|
{
|
||||||
|
name: "ban with duration and reason",
|
||||||
|
command: roomId => `!mjolnir since ${Date.now() - cutDate.getTime()}ms ban 100 "bad, bad user" ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.ban,
|
||||||
|
},
|
||||||
|
// Kick bad users in one room, using date syntax, with reason.
|
||||||
|
{
|
||||||
|
name: "kick with date and reason",
|
||||||
|
command: roomId => `!mjolnir since "${cutDate}" kick 100 "bad, bad user" ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.kick,
|
||||||
|
},
|
||||||
|
// Ban bad users in one room, using date syntax, with reason.
|
||||||
|
{
|
||||||
|
name: "ban with date and reason",
|
||||||
|
command: roomId => `!mjolnir since "${cutDate}" ban 100 "bad, bad user" ${roomId}`,
|
||||||
|
shouldAffectWitnessRoom: false,
|
||||||
|
n: 1,
|
||||||
|
method: Method.ban,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Kick bad users everywhere, no reason
|
||||||
|
{
|
||||||
|
name: "kick with date everywhere",
|
||||||
|
command: () => `!mjolnir since "${cutDate}" kick 100 "bad, bad user" *`,
|
||||||
|
shouldAffectWitnessRoom: true,
|
||||||
|
n: NUMBER_OF_ROOMS - 1,
|
||||||
|
method: Method.kick,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
for (let i = 0; i < EXPERIMENTS.length; ++i) {
|
||||||
|
const experiment = EXPERIMENTS[i];
|
||||||
|
const roomId = roomIds[i + 2];
|
||||||
|
const joined = this.mjolnir.roomJoins.getUsersInRoom(roomId, start, 100);
|
||||||
|
assert.ok(joined.length >= 2 * SAMPLE_SIZE, `We should have seen ${2 * SAMPLE_SIZE} users, saw ${joined.length}`);
|
||||||
|
await getNthReply(this.mjolnir.client, this.mjolnir.managementRoomId, experiment.n, async () => {
|
||||||
|
const command = experiment.command(roomId);
|
||||||
|
let result = await this.moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: command });
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
const usersInRoom = await this.mjolnir.client.getJoinedRoomMembers(roomId);
|
||||||
|
const usersInUnprotectedWitnessRoom = await this.mjolnir.client.getJoinedRoomMembers(WITNESS_UNPROTECTED_ROOM_ID);
|
||||||
|
const usersInWitnessRoom = await this.mjolnir.client.getJoinedRoomMembers(WITNESS_ROOM_ID);
|
||||||
|
for (let userId of goodUserIds) {
|
||||||
|
assert.ok(usersInRoom.includes(userId), `After a ${experiment.name}, good user ${userId} should still be in affected room`);
|
||||||
|
assert.ok(usersInWitnessRoom.includes(userId), `After a ${experiment.name}, good user ${userId} should still be in witness room`);
|
||||||
|
assert.ok(usersInUnprotectedWitnessRoom.includes(userId), `After a ${experiment.name}, good user ${userId} should still be in unprotected witness room`);
|
||||||
|
}
|
||||||
|
for (let userId of badUserIds) {
|
||||||
|
assert.ok(!usersInRoom.includes(userId), `After a ${experiment.name}, bad user ${userId} should NOT be in affected room`);
|
||||||
|
assert.equal(usersInWitnessRoom.includes(userId), !experiment.shouldAffectWitnessRoom, `After a ${experiment.name}, bad user ${userId} should ${experiment.shouldAffectWitnessRoom ? "NOT" : "still"} be in witness room`);
|
||||||
|
assert.ok(usersInUnprotectedWitnessRoom.includes(userId), `After a ${experiment.name}, bad user ${userId} should still be in unprotected witness room`);
|
||||||
|
const leaveEvent = await this.mjolnir.client.getRoomStateEvent(roomId, "m.room.member", userId);
|
||||||
|
switch (experiment.method) {
|
||||||
|
case Method.kick:
|
||||||
|
assert.equal(leaveEvent.membership, "leave");
|
||||||
|
break;
|
||||||
|
case Method.ban:
|
||||||
|
assert.equal(leaveEvent.membership, "ban");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
297
yarn.lock
297
yarn.lock
@ -70,11 +70,6 @@
|
|||||||
"@types/yargs" "^16.0.0"
|
"@types/yargs" "^16.0.0"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
|
|
||||||
"@napi-rs/cli@^2.2.0":
|
|
||||||
version "2.4.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/cli/-/cli-2.4.4.tgz#878a38f0fba1709d89d66eba706745ce728a61a5"
|
|
||||||
integrity sha512-f+tvwCv1ka24dBqI2DgBhR7Oxl3DKHOp4onxLXwyBFt6iCADnr3YZIr1/2Iq5r3uqxFgaf01bfPsRQZPkEp0kQ==
|
|
||||||
|
|
||||||
"@selderee/plugin-htmlparser2@^0.6.0":
|
"@selderee/plugin-htmlparser2@^0.6.0":
|
||||||
version "0.6.0"
|
version "0.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz#27e994afd1c2cb647ceb5406a185a5574188069d"
|
resolved "https://registry.yarnpkg.com/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz#27e994afd1c2cb647ceb5406a185a5574188069d"
|
||||||
@ -88,14 +83,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||||
|
|
||||||
"@turt2live/matrix-sdk-crypto-nodejs@^0.1.0-beta.10":
|
|
||||||
version "0.1.0-beta.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@turt2live/matrix-sdk-crypto-nodejs/-/matrix-sdk-crypto-nodejs-0.1.0-beta.10.tgz#9b0a8e1f48badeb37a0b0f8eb0fb6dc9bbb1949a"
|
|
||||||
integrity sha512-y5TA8fD5a7xaIwjZhQ66eT3scDsU47GkcCuQ0vjlXB0shY2cCMB4MF1nY/7c1/DniM+KvDXxrhs2VXphlPLpaA==
|
|
||||||
dependencies:
|
|
||||||
"@napi-rs/cli" "^2.2.0"
|
|
||||||
shelljs "^0.8.4"
|
|
||||||
|
|
||||||
"@types/body-parser@*":
|
"@types/body-parser@*":
|
||||||
version "1.19.1"
|
version "1.19.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c"
|
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c"
|
||||||
@ -130,7 +117,7 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/range-parser" "*"
|
"@types/range-parser" "*"
|
||||||
|
|
||||||
"@types/express@^4.17.13":
|
"@types/express@^4.17.7":
|
||||||
version "4.17.13"
|
version "4.17.13"
|
||||||
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034"
|
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034"
|
||||||
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
|
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
|
||||||
@ -145,6 +132,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-8.0.1.tgz#e449513df2283b1adedc85bdc2f6b7187f32972a"
|
resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-8.0.1.tgz#e449513df2283b1adedc85bdc2f6b7187f32972a"
|
||||||
integrity sha512-0B/OifmJYmk5r9z9+KJtGWOF0LEjbTN4D2QeCh+mAw81JkJwC83NvNWUZFEqRT5PpnjX7vX0ab1SMGcwCs3Lag==
|
integrity sha512-0B/OifmJYmk5r9z9+KJtGWOF0LEjbTN4D2QeCh+mAw81JkJwC83NvNWUZFEqRT5PpnjX7vX0ab1SMGcwCs3Lag==
|
||||||
|
|
||||||
|
"@types/humanize-duration@^3.27.1":
|
||||||
|
version "3.27.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/humanize-duration/-/humanize-duration-3.27.1.tgz#f14740d1f585a0a8e3f46359b62fda8b0eaa31e7"
|
||||||
|
integrity sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==
|
||||||
|
|
||||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
||||||
@ -216,6 +208,11 @@
|
|||||||
"@types/mime" "^1"
|
"@types/mime" "^1"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/shell-quote@^1.7.1":
|
||||||
|
version "1.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/shell-quote/-/shell-quote-1.7.1.tgz#2d059091214a02c29f003f591032172b2aff77e8"
|
||||||
|
integrity sha512-SWZ2Nom1pkyXCDohRSrkSKvDh8QOG9RfAsrt5/NsPQC4UQJ55eG0qClA40I+Gkez4KTQ0uDUT8ELRXThf3J5jw==
|
||||||
|
|
||||||
"@types/stack-utils@^2.0.0":
|
"@types/stack-utils@^2.0.0":
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
|
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
|
||||||
@ -256,6 +253,14 @@ accepts@~1.3.7:
|
|||||||
mime-types "~2.1.24"
|
mime-types "~2.1.24"
|
||||||
negotiator "0.6.2"
|
negotiator "0.6.2"
|
||||||
|
|
||||||
|
accepts@~1.3.8:
|
||||||
|
version "1.3.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
|
||||||
|
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
|
||||||
|
dependencies:
|
||||||
|
mime-types "~2.1.34"
|
||||||
|
negotiator "0.6.3"
|
||||||
|
|
||||||
acorn-globals@^6.0.0:
|
acorn-globals@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
|
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
|
||||||
@ -311,11 +316,6 @@ ajv@^8.0.1:
|
|||||||
require-from-string "^2.0.2"
|
require-from-string "^2.0.2"
|
||||||
uri-js "^4.2.2"
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
another-json@^0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/another-json/-/another-json-0.2.0.tgz#b5f4019c973b6dd5c6506a2d93469cb6d32aeedc"
|
|
||||||
integrity sha1-tfQBnJc7bdXGUGotk0acttMq7tw=
|
|
||||||
|
|
||||||
ansi-colors@4.1.1, ansi-colors@^4.1.1:
|
ansi-colors@4.1.1, ansi-colors@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
|
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
|
||||||
@ -452,20 +452,20 @@ body-parser@1.19.0:
|
|||||||
raw-body "2.4.0"
|
raw-body "2.4.0"
|
||||||
type-is "~1.6.17"
|
type-is "~1.6.17"
|
||||||
|
|
||||||
body-parser@1.19.1:
|
body-parser@1.19.2:
|
||||||
version "1.19.1"
|
version "1.19.2"
|
||||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4"
|
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e"
|
||||||
integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==
|
integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes "3.1.1"
|
bytes "3.1.2"
|
||||||
content-type "~1.0.4"
|
content-type "~1.0.4"
|
||||||
debug "2.6.9"
|
debug "2.6.9"
|
||||||
depd "~1.1.2"
|
depd "~1.1.2"
|
||||||
http-errors "1.8.1"
|
http-errors "1.8.1"
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
on-finished "~2.3.0"
|
on-finished "~2.3.0"
|
||||||
qs "6.9.6"
|
qs "6.9.7"
|
||||||
raw-body "2.4.2"
|
raw-body "2.4.3"
|
||||||
type-is "~1.6.18"
|
type-is "~1.6.18"
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
@ -508,10 +508,10 @@ bytes@3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||||
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
|
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
|
||||||
|
|
||||||
bytes@3.1.1:
|
bytes@3.1.2:
|
||||||
version "3.1.1"
|
version "3.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a"
|
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||||
integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==
|
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||||
|
|
||||||
callsites@^3.0.0:
|
callsites@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
@ -537,7 +537,7 @@ chalk@^2.0.0, chalk@^2.3.0:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
chalk@^4, chalk@^4.0.0, chalk@^4.1.0:
|
chalk@^4.0.0, chalk@^4.1.0:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||||
@ -651,10 +651,10 @@ cookie@0.4.0:
|
|||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
|
||||||
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
|
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
|
||||||
|
|
||||||
cookie@0.4.1:
|
cookie@0.4.2:
|
||||||
version "0.4.1"
|
version "0.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
|
||||||
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
|
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
|
||||||
|
|
||||||
core-util-is@1.0.2:
|
core-util-is@1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@ -815,6 +815,13 @@ domexception@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
webidl-conversions "^5.0.0"
|
webidl-conversions "^5.0.0"
|
||||||
|
|
||||||
|
domhandler@^3.0.0:
|
||||||
|
version "3.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a"
|
||||||
|
integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.0.1"
|
||||||
|
|
||||||
domhandler@^4.0.0, domhandler@^4.2.0:
|
domhandler@^4.0.0, domhandler@^4.2.0:
|
||||||
version "4.2.2"
|
version "4.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f"
|
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f"
|
||||||
@ -822,7 +829,7 @@ domhandler@^4.0.0, domhandler@^4.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
domelementtype "^2.2.0"
|
domelementtype "^2.2.0"
|
||||||
|
|
||||||
domutils@^2.5.2:
|
domutils@^2.0.0, domutils@^2.5.2:
|
||||||
version "2.8.0"
|
version "2.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
|
||||||
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
|
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
|
||||||
@ -1080,17 +1087,17 @@ express@^4.17:
|
|||||||
utils-merge "1.0.1"
|
utils-merge "1.0.1"
|
||||||
vary "~1.1.2"
|
vary "~1.1.2"
|
||||||
|
|
||||||
express@^4.17.2:
|
express@^4.17.1:
|
||||||
version "4.17.2"
|
version "4.17.3"
|
||||||
resolved "https://registry.yarnpkg.com/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3"
|
resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1"
|
||||||
integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==
|
integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==
|
||||||
dependencies:
|
dependencies:
|
||||||
accepts "~1.3.7"
|
accepts "~1.3.8"
|
||||||
array-flatten "1.1.1"
|
array-flatten "1.1.1"
|
||||||
body-parser "1.19.1"
|
body-parser "1.19.2"
|
||||||
content-disposition "0.5.4"
|
content-disposition "0.5.4"
|
||||||
content-type "~1.0.4"
|
content-type "~1.0.4"
|
||||||
cookie "0.4.1"
|
cookie "0.4.2"
|
||||||
cookie-signature "1.0.6"
|
cookie-signature "1.0.6"
|
||||||
debug "2.6.9"
|
debug "2.6.9"
|
||||||
depd "~1.1.2"
|
depd "~1.1.2"
|
||||||
@ -1105,7 +1112,7 @@ express@^4.17.2:
|
|||||||
parseurl "~1.3.3"
|
parseurl "~1.3.3"
|
||||||
path-to-regexp "0.1.7"
|
path-to-regexp "0.1.7"
|
||||||
proxy-addr "~2.0.7"
|
proxy-addr "~2.0.7"
|
||||||
qs "6.9.6"
|
qs "6.9.7"
|
||||||
range-parser "~1.2.1"
|
range-parser "~1.2.1"
|
||||||
safe-buffer "5.2.1"
|
safe-buffer "5.2.1"
|
||||||
send "0.17.2"
|
send "0.17.2"
|
||||||
@ -1288,7 +1295,7 @@ glob@7.1.7:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
glob@^7.0.0, glob@^7.1.1, glob@^7.1.3:
|
glob@^7.1.1, glob@^7.1.3:
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
|
||||||
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
|
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
|
||||||
@ -1367,6 +1374,17 @@ html-encoding-sniffer@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
whatwg-encoding "^1.0.5"
|
whatwg-encoding "^1.0.5"
|
||||||
|
|
||||||
|
html-to-text@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-6.0.0.tgz#8b48adb1b781a8378f374c5bb481864a169f59f4"
|
||||||
|
integrity sha512-r0KNC5aqCAItsjlgtirW6RW25c92Ee3ybQj8z//4Sl4suE3HIPqM4deGpYCUJULLjtVPEP1+Ma+1ZeX1iMsCiA==
|
||||||
|
dependencies:
|
||||||
|
deepmerge "^4.2.2"
|
||||||
|
he "^1.2.0"
|
||||||
|
htmlparser2 "^4.1.0"
|
||||||
|
lodash "^4.17.20"
|
||||||
|
minimist "^1.2.5"
|
||||||
|
|
||||||
html-to-text@^8.0.0:
|
html-to-text@^8.0.0:
|
||||||
version "8.0.0"
|
version "8.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-8.0.0.tgz#5848681a5a38d657a7bb58cf5006d1c29fe64ce3"
|
resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-8.0.0.tgz#5848681a5a38d657a7bb58cf5006d1c29fe64ce3"
|
||||||
@ -1379,23 +1397,21 @@ html-to-text@^8.0.0:
|
|||||||
minimist "^1.2.5"
|
minimist "^1.2.5"
|
||||||
selderee "^0.6.0"
|
selderee "^0.6.0"
|
||||||
|
|
||||||
html-to-text@^8.1.0:
|
|
||||||
version "8.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-8.1.0.tgz#0c35fc452e6eccb275669adb8bcc61d93ec43ed5"
|
|
||||||
integrity sha512-Z9iYAqYK2c18GswSbnxJSeMs7lyJgwR2oIkDOyOHGBbYsPsG4HvT379jj3Lcbfko8A5ceyyMHAfkmp/BiXA9/Q==
|
|
||||||
dependencies:
|
|
||||||
"@selderee/plugin-htmlparser2" "^0.6.0"
|
|
||||||
deepmerge "^4.2.2"
|
|
||||||
he "^1.2.0"
|
|
||||||
htmlparser2 "^6.1.0"
|
|
||||||
minimist "^1.2.5"
|
|
||||||
selderee "^0.6.0"
|
|
||||||
|
|
||||||
htmlencode@^0.0.4:
|
htmlencode@^0.0.4:
|
||||||
version "0.0.4"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/htmlencode/-/htmlencode-0.0.4.tgz#f7e2d6afbe18a87a78e63ba3308e753766740e3f"
|
resolved "https://registry.yarnpkg.com/htmlencode/-/htmlencode-0.0.4.tgz#f7e2d6afbe18a87a78e63ba3308e753766740e3f"
|
||||||
integrity sha1-9+LWr74YqHp45jujMI51N2Z0Dj8=
|
integrity sha1-9+LWr74YqHp45jujMI51N2Z0Dj8=
|
||||||
|
|
||||||
|
htmlparser2@^4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78"
|
||||||
|
integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.0.1"
|
||||||
|
domhandler "^3.0.0"
|
||||||
|
domutils "^2.0.0"
|
||||||
|
entities "^2.0.0"
|
||||||
|
|
||||||
htmlparser2@^6.0.0, htmlparser2@^6.1.0:
|
htmlparser2@^6.0.0, htmlparser2@^6.1.0:
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
||||||
@ -1470,6 +1486,11 @@ humanize-duration-ts@^2.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/humanize-duration-ts/-/humanize-duration-ts-2.1.1.tgz#5382b2789f851005a67229eaf031931d71f37ee9"
|
resolved "https://registry.yarnpkg.com/humanize-duration-ts/-/humanize-duration-ts-2.1.1.tgz#5382b2789f851005a67229eaf031931d71f37ee9"
|
||||||
integrity sha512-TibNF2/fkypjAfHdGpWL/dmWUS0G6Qi+3mKyiB6LDCowbMy+PtzbgPTnFMNTOVAJXDau01jYrJ3tFoz5AJSqhA==
|
integrity sha512-TibNF2/fkypjAfHdGpWL/dmWUS0G6Qi+3mKyiB6LDCowbMy+PtzbgPTnFMNTOVAJXDau01jYrJ3tFoz5AJSqhA==
|
||||||
|
|
||||||
|
humanize-duration@^3.27.1:
|
||||||
|
version "3.27.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.27.1.tgz#2cd4ea4b03bd92184aee6d90d77a8f3d7628df69"
|
||||||
|
integrity sha512-jCVkMl+EaM80rrMrAPl96SGG4NRac53UyI1o/yAzebDntEY6K6/Fj2HOjdPg8omTqIe5Y0wPBai2q5xXrIbarA==
|
||||||
|
|
||||||
iconv-lite@0.4.24:
|
iconv-lite@0.4.24:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
@ -1513,11 +1534,6 @@ inherits@2.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||||
|
|
||||||
interpret@^1.0.0:
|
|
||||||
version "1.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
|
|
||||||
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
|
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||||
@ -1537,13 +1553,6 @@ is-core-module@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
|
|
||||||
is-core-module@^2.8.1:
|
|
||||||
version "2.8.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
|
|
||||||
integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
|
|
||||||
dependencies:
|
|
||||||
has "^1.0.3"
|
|
||||||
|
|
||||||
is-extglob@^2.1.1:
|
is-extglob@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||||
@ -1758,6 +1767,11 @@ jsprim@^1.2.2:
|
|||||||
json-schema "0.2.3"
|
json-schema "0.2.3"
|
||||||
verror "1.10.0"
|
verror "1.10.0"
|
||||||
|
|
||||||
|
klona@^2.0.3:
|
||||||
|
version "2.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
|
||||||
|
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
|
||||||
|
|
||||||
levn@^0.4.1:
|
levn@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
|
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
|
||||||
@ -1796,7 +1810,7 @@ lodash.truncate@^4.4.2:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
||||||
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
|
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
|
||||||
|
|
||||||
lodash@4, lodash@^4.17.19, lodash@^4.7.0:
|
lodash@4, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.7.0:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
@ -1809,7 +1823,7 @@ log-symbols@4.1.0:
|
|||||||
chalk "^4.1.0"
|
chalk "^4.1.0"
|
||||||
is-unicode-supported "^0.1.0"
|
is-unicode-supported "^0.1.0"
|
||||||
|
|
||||||
lowdb@^1:
|
lowdb@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-1.0.0.tgz#5243be6b22786ccce30e50c9a33eac36b20c8064"
|
resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-1.0.0.tgz#5243be6b22786ccce30e50c9a33eac36b20c8064"
|
||||||
integrity sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==
|
integrity sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==
|
||||||
@ -1840,25 +1854,25 @@ make-error@^1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||||
|
|
||||||
"matrix-bot-sdk@file:../blurbs/matrix-bot-sdk":
|
matrix-bot-sdk@^0.5.19:
|
||||||
version "99.0.2"
|
version "0.5.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/matrix-bot-sdk/-/matrix-bot-sdk-0.5.19.tgz#6ce13359ab53ea0af9dc3ebcbe288c5f6d9c02c6"
|
||||||
|
integrity sha512-RIPyvQPkOVp2yTKeDgp5rcn6z/DiKdHb6E8c69K+utai8ypRGtfDRj0PGqP+1XzqC9Wb1OFrESCUB5t0ffdC9g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@turt2live/matrix-sdk-crypto-nodejs" "^0.1.0-beta.10"
|
"@types/express" "^4.17.7"
|
||||||
"@types/express" "^4.17.13"
|
chalk "^4.1.0"
|
||||||
another-json "^0.2.0"
|
express "^4.17.1"
|
||||||
chalk "^4"
|
|
||||||
express "^4.17.2"
|
|
||||||
glob-to-regexp "^0.4.1"
|
glob-to-regexp "^0.4.1"
|
||||||
hash.js "^1.1.7"
|
hash.js "^1.1.7"
|
||||||
html-to-text "^8.1.0"
|
html-to-text "^6.0.0"
|
||||||
htmlencode "^0.0.4"
|
htmlencode "^0.0.4"
|
||||||
lowdb "^1"
|
lowdb "^1.0.0"
|
||||||
lru-cache "^6.0.0"
|
lru-cache "^6.0.0"
|
||||||
mkdirp "^1.0.4"
|
mkdirp "^1.0.4"
|
||||||
morgan "^1.10.0"
|
morgan "^1.10.0"
|
||||||
request "^2.88.2"
|
request "^2.88.2"
|
||||||
request-promise "^4.2.6"
|
request-promise "^4.2.6"
|
||||||
sanitize-html "^2.6.1"
|
sanitize-html "^2.3.2"
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
@ -1888,6 +1902,11 @@ mime-db@1.49.0:
|
|||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
|
||||||
integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
|
integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
|
||||||
|
|
||||||
|
mime-db@1.51.0:
|
||||||
|
version "1.51.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c"
|
||||||
|
integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==
|
||||||
|
|
||||||
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
|
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
|
||||||
version "2.1.32"
|
version "2.1.32"
|
||||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5"
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5"
|
||||||
@ -1895,6 +1914,13 @@ mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime-db "1.49.0"
|
mime-db "1.49.0"
|
||||||
|
|
||||||
|
mime-types@~2.1.34:
|
||||||
|
version "2.1.34"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24"
|
||||||
|
integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==
|
||||||
|
dependencies:
|
||||||
|
mime-db "1.51.0"
|
||||||
|
|
||||||
mime@1.6.0:
|
mime@1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||||
@ -1995,15 +2021,20 @@ ms@2.1.3:
|
|||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||||
|
|
||||||
|
nanocolors@^0.2.2:
|
||||||
|
version "0.2.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/nanocolors/-/nanocolors-0.2.12.tgz#4d05932e70116078673ea4cc6699a1c56cc77777"
|
||||||
|
integrity sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug==
|
||||||
|
|
||||||
nanoid@3.1.25:
|
nanoid@3.1.25:
|
||||||
version "3.1.25"
|
version "3.1.25"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
|
||||||
integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
|
integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
|
||||||
|
|
||||||
nanoid@^3.2.0:
|
nanoid@^3.1.25:
|
||||||
version "3.3.0"
|
version "3.1.28"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.0.tgz#5906f776fd886c66c24f3653e0c46fcb1d4ad6b0"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.28.tgz#3c01bac14cb6c5680569014cc65a2f26424c6bd4"
|
||||||
integrity sha512-JzxqqT5u/x+/KOFSd7JP15DOo9nOoHpx6DYatqIHUW2+flybkm+mdcraotSQR5WcnZr+qhGVh8Ted0KdfSMxlg==
|
integrity sha512-gSu9VZ2HtmoKYe/lmyPFES5nknFrHa+/DT9muUFWFMi6Jh9E1I7bkvlQ8xxf1Kos9pi9o8lBnIOkatMhKX/YUw==
|
||||||
|
|
||||||
natural-compare@^1.4.0:
|
natural-compare@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
@ -2025,6 +2056,11 @@ negotiator@0.6.2:
|
|||||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||||
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
|
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
|
||||||
|
|
||||||
|
negotiator@0.6.3:
|
||||||
|
version "0.6.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||||
|
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||||
|
|
||||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||||
@ -2147,7 +2183,7 @@ path-key@^3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||||
|
|
||||||
path-parse@^1.0.6, path-parse@^1.0.7:
|
path-parse@^1.0.6:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||||
@ -2162,11 +2198,6 @@ performance-now@^2.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||||
|
|
||||||
picocolors@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
|
||||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
|
||||||
|
|
||||||
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
|
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
||||||
@ -2177,14 +2208,14 @@ pify@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||||
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
|
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
|
||||||
|
|
||||||
postcss@^8.3.11:
|
postcss@^8.0.2:
|
||||||
version "8.4.6"
|
version "8.3.8"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1"
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.8.tgz#9ebe2a127396b4b4570ae9f7770e7fb83db2bac1"
|
||||||
integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==
|
integrity sha512-GT5bTjjZnwDifajzczOC+r3FI3Cu+PgPvrsjhQdRqa2kTJ4968/X9CUce9xttIB0xOs5c6xf0TCWZo/y9lF6bA==
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.2.0"
|
nanocolors "^0.2.2"
|
||||||
picocolors "^1.0.0"
|
nanoid "^3.1.25"
|
||||||
source-map-js "^1.0.2"
|
source-map-js "^0.6.2"
|
||||||
|
|
||||||
prelude-ls@^1.2.1:
|
prelude-ls@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
@ -2239,10 +2270,10 @@ qs@6.7.0:
|
|||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||||
|
|
||||||
qs@6.9.6:
|
qs@6.9.7:
|
||||||
version "6.9.6"
|
version "6.9.7"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
|
||||||
integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==
|
integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
|
||||||
|
|
||||||
qs@~6.5.2:
|
qs@~6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.2"
|
||||||
@ -2284,12 +2315,12 @@ raw-body@2.4.0:
|
|||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
raw-body@2.4.2:
|
raw-body@2.4.3:
|
||||||
version "2.4.2"
|
version "2.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32"
|
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"
|
||||||
integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==
|
integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes "3.1.1"
|
bytes "3.1.2"
|
||||||
http-errors "1.8.1"
|
http-errors "1.8.1"
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
@ -2306,13 +2337,6 @@ readdirp@~3.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
picomatch "^2.2.1"
|
picomatch "^2.2.1"
|
||||||
|
|
||||||
rechoir@^0.6.2:
|
|
||||||
version "0.6.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
|
||||||
integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
|
|
||||||
dependencies:
|
|
||||||
resolve "^1.1.6"
|
|
||||||
|
|
||||||
regexpp@^3.1.0:
|
regexpp@^3.1.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
|
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
|
||||||
@ -2376,15 +2400,6 @@ resolve-from@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||||
|
|
||||||
resolve@^1.1.6:
|
|
||||||
version "1.22.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
|
|
||||||
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
|
|
||||||
dependencies:
|
|
||||||
is-core-module "^2.8.1"
|
|
||||||
path-parse "^1.0.7"
|
|
||||||
supports-preserve-symlinks-flag "^1.0.0"
|
|
||||||
|
|
||||||
resolve@^1.3.2:
|
resolve@^1.3.2:
|
||||||
version "1.20.0"
|
version "1.20.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||||
@ -2420,17 +2435,18 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||||
|
|
||||||
sanitize-html@^2.6.1:
|
sanitize-html@^2.3.2:
|
||||||
version "2.7.0"
|
version "2.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.0.tgz#e106205b468aca932e2f9baf241f24660d34e279"
|
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.5.1.tgz#f49998dc54c8180153940440d3a7294b09e4258a"
|
||||||
integrity sha512-jfQelabOn5voO7FAfnQF7v+jsA6z9zC/O4ec0z3E35XPEtHYJT/OdUziVWlKW4irCr2kXaQAyXTXDHWAibg1tA==
|
integrity sha512-hUITPitQk+eFNLtr4dEkaaiAJndG2YE87IOpcfBSL1XdklWgwcNDJdr9Ppe8QKL/C3jFt1xH/Mbj20e0GZQOfg==
|
||||||
dependencies:
|
dependencies:
|
||||||
deepmerge "^4.2.2"
|
deepmerge "^4.2.2"
|
||||||
escape-string-regexp "^4.0.0"
|
escape-string-regexp "^4.0.0"
|
||||||
htmlparser2 "^6.0.0"
|
htmlparser2 "^6.0.0"
|
||||||
is-plain-object "^5.0.0"
|
is-plain-object "^5.0.0"
|
||||||
|
klona "^2.0.3"
|
||||||
parse-srcset "^1.0.2"
|
parse-srcset "^1.0.2"
|
||||||
postcss "^8.3.11"
|
postcss "^8.0.2"
|
||||||
|
|
||||||
saxes@^5.0.1:
|
saxes@^5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
@ -2545,14 +2561,10 @@ shebang-regex@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||||
|
|
||||||
shelljs@^0.8.4:
|
shell-quote@^1.7.3:
|
||||||
version "0.8.5"
|
version "1.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
|
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
|
||||||
integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
|
integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==
|
||||||
dependencies:
|
|
||||||
glob "^7.0.0"
|
|
||||||
interpret "^1.0.0"
|
|
||||||
rechoir "^0.6.2"
|
|
||||||
|
|
||||||
sigmund@^1.0.1:
|
sigmund@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
@ -2573,10 +2585,10 @@ slice-ansi@^4.0.0:
|
|||||||
astral-regex "^2.0.0"
|
astral-regex "^2.0.0"
|
||||||
is-fullwidth-code-point "^3.0.0"
|
is-fullwidth-code-point "^3.0.0"
|
||||||
|
|
||||||
source-map-js@^1.0.2:
|
source-map-js@^0.6.2:
|
||||||
version "1.0.2"
|
version "0.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
|
||||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
|
||||||
|
|
||||||
source-map-support@^0.5.6:
|
source-map-support@^0.5.6:
|
||||||
version "0.5.20"
|
version "0.5.20"
|
||||||
@ -2682,11 +2694,6 @@ supports-color@^7.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
|
||||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
|
||||||
|
|
||||||
symbol-tree@^3.2.4:
|
symbol-tree@^3.2.4:
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||||
|
Loading…
Reference in New Issue
Block a user