Repository: ROpdebee/mb-userscripts
Pull request #783 (2024-07-26 18:56:07)

build(deps-dev): bump ws from 8.16.0 to 8.18.0
Bumps [ws](https://github.com/websockets/ws) from 8.16.0 to 8.18.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/websockets/ws/releases">ws's releases</a>.</em></p>
<blockquote>
<h2>8.18.0</h2>
<h1>Features</h1>
<ul>
<li>Added support for <code>Blob</code> (<a href="https://redirect.github.com/websockets/ws/issues/2229">#2229</a>).</li>
</ul>
<h2>8.17.1</h2>
<h1>Bug fixes</h1>
<ul>
<li>Fixed a DoS vulnerability (<a href="https://redirect.github.com/websockets/ws/issues/2231">#2231</a>).</li>
</ul>
<p>A request with a number of headers exceeding the[<code>server.maxHeadersCount</code>][]
threshold could be used to crash a ws server.</p>
<pre lang="js"><code>const http = require('http');
const WebSocket = require('ws');
<p>const wss = new WebSocket.Server({ port: 0 }, function () {
const chars = &quot;!#$%&amp;'*+-.0123456789abcdefghijklmnopqrstuvwxyz^_`|~&quot;.split('');
const headers = {};
let count = 0;</p>
<p>for (let i = 0; i &lt; chars.length; i++) {
if (count === 2000) break;</p>
<pre><code>for (let j = 0; j &amp;lt; chars.length; j++) {
  const key = chars[i] + chars[j];
  headers[key] = 'x';

  if (++count === 2000) break;
}
</code></pre>
<p>}</p>
<p>headers.Connection = 'Upgrade';
headers.Upgrade = 'websocket';
headers['Sec-WebSocket-Key'] = 'dGhlIHNhbXBsZSBub25jZQ==';
headers['Sec-WebSocket-Version'] = '13';</p>
<p>const request = http.request({
headers: headers,
host: '127.0.0.1',
port: wss.address().port
});</p>
<p>request.end();
});
</code></pre></p>
<p>The vulnerability was reported by <a href="https://github.com/rrlapointe">Ryan LaPointe</a> in <a href="https://redirect.github.com/websockets/ws/issues/2230">websockets/ws#2230</a>.</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/websockets/ws/commit/976c53c4065c49ede73bfba824caf5a6e0f290cb"><code>976c53c</code></a> [dist] 8.18.0</li>
<li><a href="https://github.com/websockets/ws/commit/59b9629b78aa66bcf9acce20468004cd3751c136"><code>59b9629</code></a> [feature] Add support for <code>Blob</code> (<a href="https://redirect.github.com/websockets/ws/issues/2229">#2229</a>)</li>
<li><a href="https://github.com/websockets/ws/commit/0d1b5e6c4acad16a6b1a1904426eb266a5ba2f72"><code>0d1b5e6</code></a> [security] Use more descriptive text for 2017 vulnerability link</li>
<li><a href="https://github.com/websockets/ws/commit/15f11a052a231d1f819fffef53bf4b287646d1ca"><code>15f11a0</code></a> [security] Add new DoS vulnerability to SECURITY.md</li>
<li><a href="https://github.com/websockets/ws/commit/3c56601092872f7d7566989f0e379271afd0e4a1"><code>3c56601</code></a> [dist] 8.17.1</li>
<li><a href="https://github.com/websockets/ws/commit/e55e5106f10fcbaac37cfa89759e4cc0d073a52c"><code>e55e510</code></a> [security] Fix crash when the Upgrade header cannot be read (<a href="https://redirect.github.com/websockets/ws/issues/2231">#2231</a>)</li>
<li><a href="https://github.com/websockets/ws/commit/6a00029edd924499f892aed8003cef1fa724cfe5"><code>6a00029</code></a> [test] Increase code coverage</li>
<li><a href="https://github.com/websockets/ws/commit/ddfe4a804d79e7788ab136290e609f91cf68423f"><code>ddfe4a8</code></a> [perf] Reduce the amount of <code>crypto.randomFillSync()</code> calls</li>
<li><a href="https://github.com/websockets/ws/commit/b73b11828d166e9692a9bffe9c01a7e93bab04a8"><code>b73b118</code></a> [dist] 8.17.0</li>
<li><a href="https://github.com/websockets/ws/commit/29694a5905fa703e86667928e6bacac397469471"><code>29694a5</code></a> [test] Use the <code>highWaterMark</code> variable</li>
<li>Additional commits viewable in <a href="https://github.com/websockets/ws/compare/8.16.0...8.18.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ws&package-manager=npm_and_yarn&previous-version=8.16.0&new-version=8.18.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/ROpdebee/mb-userscripts/network/alerts).

</details>


Patch:
diff --git a/package-lock.json b/package-lock.json
index 22404248..42188f80 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5934,12 +5934,12 @@
       }
     },
     "node_modules/braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
       "dev": true,
       "dependencies": {
-        "fill-range": "^7.0.1"
+        "fill-range": "^7.1.1"
       },
       "engines": {
         "node": ">=8"
@@ -8075,9 +8075,9 @@
       }
     },
     "node_modules/fill-range": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
       "dev": true,
       "dependencies": {
         "to-regex-range": "^5.0.1"
@@ -11452,8 +11452,9 @@
     },
     "node_modules/nativejsx": {
       "version": "4.3.0",
-      "resolved": "git+ssh://git@github.com/ROpdebee/nativejsx.git#f2bed01d621bb158134e13ed3abb9be9e265cd00",
+      "resolved": "git+ssh://git@github.com/ROpdebee/nativejsx.git#dc9d4694ff92c78f76b153e44af69948b035a5a4",
       "dev": true,
+      "license": "MIT",
       "dependencies": {
         "acorn": "^8.3.0",
         "acorn-jsx": "^5.3.1",
@@ -15580,9 +15581,9 @@
       "dev": true
     },
     "node_modules/ws": {
-      "version": "8.16.0",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
-      "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
+      "version": "8.18.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+      "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
       "dev": true,
       "engines": {
         "node": ">=10.0.0"
diff --git a/src/mb_enhanced_cover_art_uploads/docs/supported_providers.md b/src/mb_enhanced_cover_art_uploads/docs/supported_providers.md
index 7f47f366..1c738229 100644
--- a/src/mb_enhanced_cover_art_uploads/docs/supported_providers.md
+++ b/src/mb_enhanced_cover_art_uploads/docs/supported_providers.md
@@ -29,7 +29,7 @@ The following table describes the types of links supported by MB: Upload to CAA
 | Qobuz | ✔️ | ✔️ | Goodies are grabbed whenever possible. Back covers might not be supported at this time, if you have a release with a back cover, please let me know. Maximised to original source image. |
 | RateYourMusic | ✔️ | ✔️ | Requires being logged in to RYM. |
 | Rockipedia | ✔️ | ❌ |
-| Soundcloud | ✔️ | ✔️ | Grabs custom track images. |
+| SoundCloud | ✔️ | ✔️ | Grabs custom track images. |
 | Spotify | ✔️ | ✔️ |
 | Tidal | ✔️ | ✔️ | listen.tidal.com/store.tidal.com are converted to tidal.com prior to fetching |
 | Traxsource | ✔️ | ✔️ | Limited to 600x600. |
diff --git a/src/mb_enhanced_cover_art_uploads/providers/base.ts b/src/mb_enhanced_cover_art_uploads/providers/base.ts
index fde8ad7f..9da9b78b 100644
--- a/src/mb_enhanced_cover_art_uploads/providers/base.ts
+++ b/src/mb_enhanced_cover_art_uploads/providers/base.ts
@@ -163,7 +163,7 @@ export abstract class ProviderWithTrackImages extends CoverArtProvider {
     // Providers that provide track images which need to be deduplicated. The
     // base class supports deduping by URL and thumbnail content.
     //
-    // Some providers, like Soundcloud and sometimes Bandcamp, use unique URLs
+    // Some providers, like SoundCloud and sometimes Bandcamp, use unique URLs
     // for each track image, so deduplicating based on URL won't work. They may
     // also not return any headers that uniquely identify the image (like a
     // Digest or an ETag), so we need to load the image and compare its data
diff --git a/src/mb_enhanced_cover_art_uploads/providers/index.ts b/src/mb_enhanced_cover_art_uploads/providers/index.ts
index 9609a182..4cd5d2ea 100644
--- a/src/mb_enhanced_cover_art_uploads/providers/index.ts
+++ b/src/mb_enhanced_cover_art_uploads/providers/index.ts
@@ -25,7 +25,7 @@ import { NetEaseProvider } from './netease';
 import { QobuzProvider } from './qobuz';
 import { RateYourMusicProvider } from './rateyourmusic';
 import { RockipediaProvider } from './rockipedia';
-import { SoundcloudProvider } from './soundcloud';
+import { SoundCloudProvider } from './soundcloud';
 import { SpotifyProvider } from './spotify';
 import { TidalProvider } from './tidal';
 import { TraxsourceProvider } from './traxsource';
@@ -68,7 +68,7 @@ addProvider(new QobuzProvider());
 addProvider(new RateYourMusicProvider());
 addProvider(new RockipediaProvider());
 addProvider(new SevenDigitalProvider());
-addProvider(new SoundcloudProvider());
+addProvider(new SoundCloudProvider());
 addProvider(new SpotifyProvider());
 addProvider(new TidalProvider());
 addProvider(new TraxsourceProvider());
diff --git a/src/mb_enhanced_cover_art_uploads/providers/soundcloud.ts b/src/mb_enhanced_cover_art_uploads/providers/soundcloud.ts
index 72abdb98..ab1def5c 100644
--- a/src/mb_enhanced_cover_art_uploads/providers/soundcloud.ts
+++ b/src/mb_enhanced_cover_art_uploads/providers/soundcloud.ts
@@ -51,11 +51,11 @@ const SC_CLIENT_ID_REGEX = /client_id\s*:\s*"([a-zA-Z\d]{32})"/;
 const SC_CLIENT_ID_CACHE_KEY = 'ROpdebee_ECAU_SC_ID';
 const SC_HOMEPAGE = 'https://soundcloud.com/';
 
-export class SoundcloudProvider extends ProviderWithTrackImages {
+export class SoundCloudProvider extends ProviderWithTrackImages {
     public readonly supportedDomains = ['soundcloud.com'];
     public readonly favicon = 'https://a-v2.sndcdn.com/assets/images/sc-icons/favicon-2cadd14bdb.ico';
-    public readonly name = 'Soundcloud';
-    // Soundcloud's URL scheme is a bit complicated, so instead of creating overly
+    public readonly name = 'SoundCloud';
+    // SoundCloud's URL scheme is a bit complicated, so instead of creating overly
     // complex regular expressions, we'll match URLs programmatically. However,
     // we still need to define this field, even though it'll never be used.
     protected readonly urlRegex = [];
@@ -88,7 +88,7 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
             }
         }
 
-        throw new Error('Could not extract Soundcloud Client ID');
+        throw new Error('Could not extract SoundCloud Client ID');
     }
 
     private static async getClientID(): Promise<string> {
@@ -106,7 +106,7 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
         const oldId = await this.getClientID();
         const newId = await this.loadClientID();
 
-        assert(oldId !== newId, 'Attempted to refresh Soundcloud Client ID but retrieved the same one.');
+        assert(oldId !== newId, 'Attempted to refresh SoundCloud Client ID but retrieved the same one.');
         localStorage.setItem(SC_CLIENT_ID_CACHE_KEY, newId);
     }
 
@@ -120,10 +120,10 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
             .split('/');
 
         return (pathParts.length > 0
-            && !SoundcloudProvider.badArtistIDs.has(artistId)
+            && !SoundCloudProvider.badArtistIDs.has(artistId)
             // artist/likes, artist/track/recommended, artist/sets, ...
             // but not artist/sets/setname!
-            && !SoundcloudProvider.badSubpaths.has(urlBasename(url)));
+            && !SoundCloudProvider.badSubpaths.has(urlBasename(url)));
     }
 
     public override extractId(url: URL): string | undefined {
@@ -141,7 +141,7 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
         const metadata = this.extractMetadataFromJS(pageContent)
             ?.find((data) => ['sound', 'playlist'].includes(data.hydratable));
         if (!metadata) {
-            throw new Error('Could not extract metadata from Soundcloud page. The release may have been removed.');
+            throw new Error('Could not extract metadata from SoundCloud page. The release may have been removed.');
         }
 
         if (metadata.hydratable === 'sound') {
@@ -175,7 +175,7 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
             covers.push(...backdrops.map((backdropUrl) => ({
                 url: new URL(backdropUrl),
                 types: [ArtworkTypeIDs.Other],
-                comment: 'Soundcloud backdrop',
+                comment: 'SoundCloud backdrop',
             })));
         }
 
@@ -195,7 +195,7 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
         // Don't bother extracting track covers if they won't be used anyway
         if (onlyFront) return covers;
 
-        // Soundcloud page only contains data for the first 5 tracks at first,
+        // SoundCloud page only contains data for the first 5 tracks at first,
         // we need to load the rest of the tracks.
         const tracks = await this.lazyLoadTracks(metadata.data.tracks);
 
@@ -215,7 +215,7 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
                 trackImages.push(...visuals.map((visualUrl) => ({
                     url: visualUrl,
                     trackNumber: (trackNumber + 1).toString(),
-                    customCommentPrefix: ['Soundcloud backdrop for track', 'Soundcloud backdrop for tracks'] as [string, string],
+                    customCommentPrefix: ['SoundCloud backdrop for track', 'SoundCloud backdrop for tracks'] as [string, string],
                 })));
 
                 return trackImages;
@@ -235,7 +235,7 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
         try {
             trackData = await this.getTrackData(lazyTrackIDs);
         } catch (error) {
-            LOGGER.error('Failed to load Soundcloud track data, some track images may be missed', error);
+            LOGGER.error('Failed to load SoundCloud track data, some track images may be missed', error);
             // We'll still return the tracks that we couldn't load, otherwise
             // the track indices will be wrong.
             return tracks;
@@ -260,8 +260,8 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
     }
 
     private async getTrackData(lazyTrackIDs: number[], firstTry = true): Promise<SCHydrationTrack[]> {
-        LOGGER.info('Loading Soundcloud track data');
-        const clientId = await SoundcloudProvider.getClientID();
+        LOGGER.info('Loading SoundCloud track data');
+        const clientId = await SoundCloudProvider.getClientID();
 
         // TODO: Does this work still work if we pass a large list of IDs?
         const parameters = new URLSearchParams({
@@ -278,11 +278,11 @@ export class SoundcloudProvider extends ProviderWithTrackImages {
             }
 
             LOGGER.debug('Attempting to refresh client ID');
-            await SoundcloudProvider.refreshClientID();
+            await SoundCloudProvider.refreshClientID();
             return this.getTrackData(lazyTrackIDs, firstTry = false);
         }
 
-        return safeParseJSON<LoadedAPITrack[]>(trackDataResponse.text, 'Failed to parse Soundcloud API response');
+        return safeParseJSON<LoadedAPITrack[]>(trackDataResponse.text, 'Failed to parse SoundCloud API response');
     }
 
     private extractVisuals(track: SCHydrationTrack): string[] {


Test patch:
diff --git a/tests/unit/mb_enhanced_cover_art_uploads/providers/soundcloud.test.ts b/tests/unit/mb_enhanced_cover_art_uploads/providers/soundcloud.test.ts
index 538f62b7..d5b71818 100644
--- a/tests/unit/mb_enhanced_cover_art_uploads/providers/soundcloud.test.ts
+++ b/tests/unit/mb_enhanced_cover_art_uploads/providers/soundcloud.test.ts
@@ -1,6 +1,6 @@
 import { LOGGER } from '@lib/logging/logger';
 import { ArtworkTypeIDs } from '@lib/MB/cover-art';
-import { SoundcloudProvider } from '@src/mb_enhanced_cover_art_uploads/providers/soundcloud';
+import { SoundCloudProvider } from '@src/mb_enhanced_cover_art_uploads/providers/soundcloud';
 import { setupPolly } from '@test-utils/pollyjs';
 import { itBehavesLike } from '@test-utils/shared-behaviour';
 
@@ -16,7 +16,7 @@ afterEach(() => {
 });
 
 describe('soundcloud provider', () => {
-    const provider = new SoundcloudProvider();
+    const provider = new SoundCloudProvider();
     const pollyContext = setupPolly();
 
     describe('url matching', () => {
@@ -113,7 +113,7 @@ describe('soundcloud provider', () => {
                 index: 3,
                 urlPart: '9b0d4395-cc72-4aa9-84e1-17b807264e2f',
                 types: [ArtworkTypeIDs.Track],
-                comment: 'Soundcloud backdrop for tracks 2, 4, 6, 8, 10, 18, 20',
+                comment: 'SoundCloud backdrop for tracks 2, 4, 6, 8, 10, 18, 20',
             }],
         }];
 
@@ -168,7 +168,7 @@ describe('soundcloud provider', () => {
             const covers = await provider.findImages(new URL('https://soundcloud.com/soundcloud/sets/i-am-other-vol-2'));
 
             expect(covers).toBeArrayOfSize(6);
-            expect(mockLoggerError).toHaveBeenCalledWith('Failed to load Soundcloud track data, some track images may be missed', expect.any(Error));
+            expect(mockLoggerError).toHaveBeenCalledWith('Failed to load SoundCloud track data, some track images may be missed', expect.any(Error));
         });
 
         it('attempts to refresh client ID', async () => {