Преглед изворни кода

Merge branch 'master' into fix/import-service

Yuki Takei пре 1 година
родитељ
комит
32d8507f5f

+ 3 - 1
.github/workflows/reusable-app-prod.yml

@@ -348,7 +348,9 @@ jobs:
 
     runs-on: ubuntu-latest
     container:
-      image: mcr.microsoft.com/playwright:latest
+      # Match the Playwright version
+      # https://github.com/microsoft/playwright/issues/20010
+      image: mcr.microsoft.com/playwright:v1.46.0-jammy
 
     strategy:
       fail-fast: false

+ 1 - 1
apps/app/package.json

@@ -209,7 +209,7 @@
     "usehooks-ts": "^2.6.0",
     "validator": "^13.7.0",
     "ws": "^8.17.1",
-    "xss": "^1.0.14",
+    "xss": "^1.0.15",
     "y-mongodb-provider": "^0.2.0",
     "y-socket.io": "^1.1.3",
     "yjs": "^13.6.18"

+ 1 - 1
apps/app/src/client/components/Admin/AuditLog/ActivityTable.tsx

@@ -15,7 +15,7 @@ type Props = {
   activityList: IActivityHasId[]
 }
 
-const formatDate = (date) => {
+const formatDate = (date: Date): string => {
   return format(new Date(date), 'yyyy/MM/dd HH:mm:ss');
 };
 

+ 1 - 1
apps/app/src/features/external-user-group/server/routes/apiv3/external-user-group-relation.ts

@@ -4,7 +4,7 @@ import type { Router, Request } from 'express';
 import type { IExternalUserGroupRelationHasId } from '~/features/external-user-group/interfaces/external-user-group';
 import ExternalUserGroupRelation from '~/features/external-user-group/server/models/external-user-group-relation';
 import type Crowi from '~/server/crowi';
-import { serializeUserGroupRelationSecurely } from '~/server/models/serializers';
+import { serializeUserGroupRelationSecurely } from '~/server/models/serializers/user-group-relation-serializer';
 import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import loggerFactory from '~/utils/logger';
 

+ 1 - 1
apps/app/src/server/models/attachment.ts

@@ -3,7 +3,7 @@ import path from 'path';
 import type { IAttachment } from '@growi/core';
 import { addSeconds } from 'date-fns/addSeconds';
 import {
-  Schema, type Model, type Document, Types,
+  Schema, type Model, type Document,
 } from 'mongoose';
 import mongoosePaginate from 'mongoose-paginate-v2';
 import uniqueValidator from 'mongoose-unique-validator';

+ 1 - 0
apps/app/src/server/routes/apiv3/activity.ts

@@ -97,6 +97,7 @@ module.exports = (crowi: Crowi): Router => {
       const paginateResult = await Activity.paginate(
         query,
         {
+          lean: true,
           limit,
           offset,
           sort: { createdAt: -1 },

+ 2 - 1
apps/app/src/server/routes/apiv3/bookmarks.js

@@ -1,6 +1,7 @@
+import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
+
 import { SupportedAction, SupportedTargetModel } from '~/interfaces/activity';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
-import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import { serializeBookmarkSecurely } from '~/server/models/serializers/bookmark-serializer';
 import { preNotifyService } from '~/server/service/pre-notify';
 import loggerFactory from '~/utils/logger';

+ 1 - 1
apps/app/src/server/routes/apiv3/page/update-page.ts

@@ -3,6 +3,7 @@ import type {
   IPage, IRevisionHasId, IUserHasId,
 } from '@growi/core';
 import { ErrorV3 } from '@growi/core/dist/models';
+import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import type { Request, RequestHandler } from 'express';
 import type { ValidationChain } from 'express-validator';
 import { body } from 'express-validator';
@@ -16,7 +17,6 @@ import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity
 import { GlobalNotificationSettingEvent } from '~/server/models/GlobalNotificationSetting';
 import type { PageDocument, PageModel } from '~/server/models/page';
 import { serializePageSecurely, serializeRevisionSecurely } from '~/server/models/serializers';
-import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import { preNotifyService } from '~/server/service/pre-notify';
 import { normalizeLatestRevisionIfBroken } from '~/server/service/revision/normalize-latest-revision-if-broken';
 import { getYjsService } from '~/server/service/yjs';

+ 1 - 1
apps/app/src/server/routes/apiv3/pages/index.js

@@ -1,6 +1,7 @@
 
 import { PageGrant } from '@growi/core';
 import { ErrorV3 } from '@growi/core/dist/models';
+import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import { isCreatablePage, isTrashPage, isUserPage } from '@growi/core/dist/utils/page-path-utils';
 import { normalizePath, addHeadingSlash } from '@growi/core/dist/utils/path-utils';
 import express from 'express';
@@ -17,7 +18,6 @@ import { generateAddActivityMiddleware } from '../../../middlewares/add-activity
 import { apiV3FormValidator } from '../../../middlewares/apiv3-form-validator';
 import { excludeReadOnlyUser } from '../../../middlewares/exclude-read-only-user';
 import { serializePageSecurely } from '../../../models/serializers/page-serializer';
-import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import { isV5ConversionError } from '../../../models/vo/v5-conversion-error';
 
 

+ 2 - 1
apps/app/src/server/routes/comment.js

@@ -1,10 +1,11 @@
 
+import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
+
 import { Comment, CommentEvent, commentEvent } from '~/features/comment/server';
 import { SupportedAction, SupportedTargetModel, SupportedEventModel } from '~/interfaces/activity';
 import loggerFactory from '~/utils/logger';
 
 import { GlobalNotificationSettingEvent } from '../models/GlobalNotificationSetting';
-import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import { preNotifyService } from '../service/pre-notify';
 
 /**

+ 1 - 1
apps/app/src/server/service/search.ts

@@ -1,4 +1,5 @@
 import type { IPageHasId } from '@growi/core';
+import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import mongoose from 'mongoose';
 import { FilterXSS } from 'xss';
 
@@ -13,7 +14,6 @@ import type {
 } from '../interfaces/search';
 import NamedQuery from '../models/named-query';
 import type { PageModel } from '../models/page';
-import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import { SearchError } from '../models/vo/search-error';
 import { hasIntersection } from '../util/compare-objectId';
 

+ 1 - 1
package.json

@@ -57,7 +57,7 @@
   "devDependencies": {
     "@changesets/changelog-github": "^0.5.0",
     "@changesets/cli": "^2.27.3",
-    "@playwright/test": "^1.45.0",
+    "@playwright/test": "^1.46.0",
     "@swc-node/register": "^1.9.1",
     "@swc/core": "^1.5.25",
     "@swc/helpers": "^0.5.11",

+ 2 - 1
packages/remark-attachment-refs/package.json

@@ -53,7 +53,8 @@
     "hast-util-select": "^5.0.5",
     "mongoose": "^6.11.3",
     "swr": "^2.0.3",
-    "universal-bunyan": "^0.9.2"
+    "universal-bunyan": "^0.9.2",
+    "xss": "^1.0.15"
   },
   "devDependencies": {
     "csstype": "^3.0.2",

+ 5 - 1
packages/remark-attachment-refs/src/client/components/RefsImg.tsx

@@ -50,7 +50,7 @@ export const RefsImgSubstance = React.memo(({
       width, height, maxWidth, maxHeight,
       display, grid, gridGap, noCarousel]);
 
-  const { data, error, isLoading } = useSWRxRefs(pagePath, prefix, {
+  const { data, error: axiosError, isLoading } = useSWRxRefs(pagePath, prefix, {
     depth,
     regexp,
     width,
@@ -64,6 +64,10 @@ export const RefsImgSubstance = React.memo(({
   }, isImmutable);
   const attachments = data != null ? data : [];
 
+  const error = axiosError != null
+    ? new Error(axiosError.response?.data ?? axiosError.message)
+    : undefined;
+
   return (
     <AttachmentList
       refsContext={refsContext}

+ 10 - 5
packages/remark-attachment-refs/src/client/stores/refs.tsx

@@ -1,6 +1,9 @@
-import { IAttachmentHasId } from '@growi/core';
+import type { IAttachmentHasId } from '@growi/core';
+import type { AxiosError } from 'axios';
 import axios from 'axios';
-import useSWR, { SWRResponse } from 'swr';
+import type { SWRResponse } from 'swr';
+// eslint-disable-next-line camelcase
+import useSWR, { unstable_serialize } from 'swr';
 
 export const useSWRxRef = (
     pagePath: string, fileNameOrId: string, isImmutable?: boolean,
@@ -27,10 +30,12 @@ export const useSWRxRef = (
 
 export const useSWRxRefs = (
     pagePath: string, prefix?: string, options?: Record<string, string | undefined>, isImmutable?: boolean,
-): SWRResponse<IAttachmentHasId[], Error> => {
+): SWRResponse<IAttachmentHasId[], AxiosError<string>> => {
+  const serializedOptions = unstable_serialize(options);
+
   return useSWR(
-    ['/_api/attachment-refs/refs', pagePath, prefix, options, isImmutable],
-    ([endpoint, pagePath, prefix, options]) => {
+    ['/_api/attachment-refs/refs', pagePath, prefix, serializedOptions, isImmutable],
+    async([endpoint, pagePath, prefix]) => {
       return axios.get(endpoint, {
         params: {
           pagePath,

+ 55 - 50
packages/remark-attachment-refs/src/server/routes/refs.ts

@@ -5,6 +5,7 @@ import type { Request } from 'express';
 import { Router } from 'express';
 import type { Model, HydratedDocument } from 'mongoose';
 import mongoose, { model, Types } from 'mongoose';
+import { FilterXSS } from 'xss';
 
 import loggerFactory from '../../utils/logger';
 
@@ -14,6 +15,55 @@ const logger = loggerFactory('growi:remark-attachment-refs:routes:refs');
 type RequestWithUser = Request & { user: HydratedDocument<IUser> };
 
 
+function generateRegexp(expression: string): RegExp {
+  // https://regex101.com/r/uOrwqt/2
+  const matches = expression.match(/^\/(.+)\/(.*)?$/);
+
+  return (matches != null)
+    ? new RegExp(matches[1], matches[2])
+    : new RegExp(expression);
+}
+
+/**
+ * add depth condition that limit fetched pages
+ *
+ * @param {any} query
+ * @param {any} pagePath
+ * @param {any} optionsDepth
+ * @returns query
+ */
+function addDepthCondition(query, pagePath, optionsDepth) {
+  // when option strings is 'depth=', the option value is true
+  if (optionsDepth == null || optionsDepth === true) {
+    throw new Error('The value of depth option is invalid.');
+  }
+
+  const range = OptionParser.parseRange(optionsDepth);
+
+  if (range == null) {
+    return query;
+  }
+
+  const start = range.start;
+  const end = range.end;
+
+  if (start < 1 || end < 1) {
+    throw new Error(`specified depth is [${start}:${end}] : start and end are must be larger than 1`);
+  }
+
+  // count slash
+  const slashNum = pagePath.split('/').length - 1;
+  const depthStart = slashNum; // start is not affect to fetch page
+  const depthEnd = slashNum + end - 1;
+
+  return query.and({
+    path: new RegExp(`^(\\/[^\\/]*){${depthStart},${depthEnd}}$`),
+  });
+}
+
+
+type RequestWithUser = Request & { user: HydratedDocument<IUser> };
+
 const loginRequiredFallback = (req, res) => {
   return res.status(403).send('login required');
 };
@@ -33,52 +83,6 @@ export const routesFactory = (crowi): any => {
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   const { PageQueryBuilder } = Page as any;
 
-  function generateRegexp(expression: string): RegExp {
-    // https://regex101.com/r/uOrwqt/2
-    const matches = expression.match(/^\/(.+)\/(.*)?$/);
-
-    return (matches != null)
-      ? new RegExp(matches[1], matches[2])
-      : new RegExp(expression);
-  }
-
-  /**
-   * add depth condition that limit fetched pages
-   *
-   * @param {any} query
-   * @param {any} pagePath
-   * @param {any} optionsDepth
-   * @returns query
-   */
-  function addDepthCondition(query, pagePath, optionsDepth) {
-    // when option strings is 'depth=', the option value is true
-    if (optionsDepth == null || optionsDepth === true) {
-      throw new Error('The value of depth option is invalid.');
-    }
-
-    const range = OptionParser.parseRange(optionsDepth);
-
-    if (range == null) {
-      return query;
-    }
-
-    const start = range.start;
-    const end = range.end;
-
-    if (start < 1 || end < 1) {
-      throw new Error(`specified depth is [${start}:${end}] : start and end are must be larger than 1`);
-    }
-
-    // count slash
-    const slashNum = pagePath.split('/').length - 1;
-    const depthStart = slashNum; // start is not affect to fetch page
-    const depthEnd = slashNum + end - 1;
-
-    return query.and({
-      path: new RegExp(`^(\\/[^\\/]*){${depthStart},${depthEnd}}$`),
-    });
-  }
-
   /**
    * return an Attachment model
    */
@@ -139,7 +143,7 @@ export const routesFactory = (crowi): any => {
   router.get('/refs', accessTokenParser, loginRequired, async(req: RequestWithUser, res) => {
     const user = req.user;
     const { prefix, pagePath } = req.query;
-    const options = JSON.parse(req.query.options?.toString() ?? '');
+    const options: Record<string, string | undefined> = JSON.parse(req.query.options?.toString() ?? '');
 
     // check either 'prefix' or 'pagePath ' is specified
     if (prefix == null && pagePath == null) {
@@ -148,8 +152,8 @@ export const routesFactory = (crowi): any => {
     }
 
     // check regex
-    let regex;
-    const regexOptionValue = options.regexp || options.regex;
+    let regex: RegExp | null = null;
+    const regexOptionValue = options.regexp ?? options.regex;
     if (regexOptionValue != null) {
       // check the length to avoid ReDoS
       if (regexOptionValue.length > 400) {
@@ -190,7 +194,8 @@ export const routesFactory = (crowi): any => {
       }
     }
     catch (err) {
-      return res.status(400).send(err);
+      const filterXSS = new FilterXSS();
+      return res.status(400).send(filterXSS.process(err.toString()));
     }
 
     const results = await pageQuery.select('id').exec();

+ 23 - 46
yarn.lock

@@ -2178,10 +2178,12 @@
     "@growi/ui" "link:packages/ui"
     axios "^0.24.0"
     bunyan "^1.8.15"
+    express "^4.19.2"
     hast-util-select "^5.0.5"
     mongoose "^6.11.3"
     swr "^2.0.3"
     universal-bunyan "^0.9.2"
+    xss "^1.0.15"
 
 "@growi/remark-drawio@link:packages/remark-drawio":
   version "1.0.0"
@@ -3132,12 +3134,12 @@
     tiny-glob "^0.2.9"
     tslib "^2.4.0"
 
-"@playwright/test@^1.45.0":
-  version "1.45.0"
-  resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.45.0.tgz#790a66165a46466c0d7099dd260881802f5aba7e"
-  integrity sha512-TVYsfMlGAaxeUllNkywbwek67Ncf8FRGn8ZlRdO291OL3NjG9oMbfVhyP82HQF0CZLMrYsvesqoUekxdWuF9Qw==
+"@playwright/test@^1.46.0":
+  version "1.46.0"
+  resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.46.0.tgz#ccea6d22c40ee7fa567e4192fafbdf2a907e2714"
+  integrity sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==
   dependencies:
-    playwright "1.45.0"
+    playwright "1.46.0"
 
 "@polka/url@^1.0.0-next.24":
   version "1.0.0-next.25"
@@ -14901,17 +14903,17 @@ plantuml-encoder@^1.2.5, plantuml-encoder@^1.4.0:
   resolved "https://registry.yarnpkg.com/plantuml-encoder/-/plantuml-encoder-1.4.0.tgz#7899302cf785de956bf1a167e15420feee5975f7"
   integrity sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==
 
-playwright-core@1.45.0:
-  version "1.45.0"
-  resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.45.0.tgz#5741a670b7c9060ce06852c0051d84736fb94edc"
-  integrity sha512-lZmHlFQ0VYSpAs43dRq1/nJ9G/6SiTI7VPqidld9TDefL9tX87bTKExWZZUF5PeRyqtXqd8fQi2qmfIedkwsNQ==
+playwright-core@1.46.0:
+  version "1.46.0"
+  resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.46.0.tgz#2336ac453a943abf0dc95a76c117f9d3ebd390eb"
+  integrity sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==
 
-playwright@1.45.0:
-  version "1.45.0"
-  resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.45.0.tgz#400c709c64438690f13705cb9c88ef93089c5c27"
-  integrity sha512-4z3ac3plDfYzGB6r0Q3LF8POPR20Z8D0aXcxbJvmfMgSSq1hkcgvFRXJk9rUq5H/MJ0Ktal869hhOdI/zUTeLA==
+playwright@1.46.0:
+  version "1.46.0"
+  resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.46.0.tgz#c7ff490deae41fc1e814bf2cb62109dd9351164d"
+  integrity sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==
   dependencies:
-    playwright-core "1.45.0"
+    playwright-core "1.46.0"
   optionalDependencies:
     fsevents "2.3.2"
 
@@ -17250,7 +17252,7 @@ string-template@>=1.0.0:
   resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96"
   integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y=
 
-"string-width-cjs@npm:string-width@^4.2.0":
+"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
   version "4.2.3"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
   integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -17268,15 +17270,6 @@ string-width@=4.2.2:
     is-fullwidth-code-point "^3.0.0"
     strip-ansi "^6.0.0"
 
-"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
-  version "4.2.3"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
-  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
-  dependencies:
-    emoji-regex "^8.0.0"
-    is-fullwidth-code-point "^3.0.0"
-    strip-ansi "^6.0.1"
-
 string-width@^5.0.1, string-width@^5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
@@ -17360,7 +17353,7 @@ stringify-entities@^4.0.0:
     character-entities-html4 "^2.0.0"
     character-entities-legacy "^3.0.0"
 
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
   integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -17374,13 +17367,6 @@ strip-ansi@^3.0.0:
   dependencies:
     ansi-regex "^2.0.0"
 
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
-  version "6.0.1"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
-  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
-  dependencies:
-    ansi-regex "^5.0.1"
-
 strip-ansi@^7.0.1, strip-ansi@^7.1.0:
   version "7.1.0"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -19202,7 +19188,7 @@ word-wrap@^1.2.3:
   resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
   integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
 
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
   integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -19220,15 +19206,6 @@ wrap-ansi@^6.2.0:
     string-width "^4.1.0"
     strip-ansi "^6.0.0"
 
-wrap-ansi@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
-  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
-  dependencies:
-    ansi-styles "^4.0.0"
-    string-width "^4.1.0"
-    strip-ansi "^6.0.0"
-
 wrap-ansi@^8.1.0:
   version "8.1.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
@@ -19366,10 +19343,10 @@ xpath@0.0.32:
   resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.32.tgz#1b73d3351af736e17ec078d6da4b8175405c48af"
   integrity sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==
 
-xss@^1.0.14:
-  version "1.0.14"
-  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.14.tgz#4f3efbde75ad0d82e9921cc3c95e6590dd336694"
-  integrity sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==
+xss@^1.0.14, xss@^1.0.15:
+  version "1.0.15"
+  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.15.tgz#96a0e13886f0661063028b410ed1b18670f4e59a"
+  integrity sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==
   dependencies:
     commander "^2.20.3"
     cssfilter "0.0.10"