From 6fa73a2e26fe5eb282a2a0b3ee9d6e5c888a4525 Mon Sep 17 00:00:00 2001 From: tamaina Date: Fri, 29 Aug 2025 16:17:10 +0900 Subject: [PATCH] =?UTF-8?q?=E4=BB=95=E6=A7=98=E5=A4=89=E6=9B=B4:=20URL?= =?UTF-8?q?=E3=81=AE=E6=9C=80=E5=BE=8C=E3=81=8C@username=E3=81=A7=E7=B5=82?= =?UTF-8?q?=E3=82=8F=E3=81=A3=E3=81=A6=E3=81=84=E3=82=8B=E5=A0=B4=E5=90=88?= =?UTF-8?q?=E3=81=AB=E3=81=A0=E3=81=91acct=20like=20url=E3=81=A8=E3=81=97?= =?UTF-8?q?=E3=81=A6=E8=AA=8D=E7=9F=A5=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/misskey-js/src/acct.ts | 7 ++++++- packages/misskey-js/test/acct.ts | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/misskey-js/src/acct.ts b/packages/misskey-js/src/acct.ts index 74e0ff06f0..e30599b650 100644 --- a/packages/misskey-js/src/acct.ts +++ b/packages/misskey-js/src/acct.ts @@ -29,8 +29,13 @@ export function parse(acct: string): Acct { export function parseUrl(str: string): Acct { const url = new URL(str); - const path = url.pathname.split('/').find((p) => p.startsWith('@') && p.length >= 2); + const splited = url.pathname.split('/'); + let path = splited.pop(); + if (path === '') path = splited.pop(); // If the last segment is empty due to a trailing '/', use the previous segment + if (!path) throw new Error('This url is not acct like.'); + if (!path.startsWith('@')) throw new Error('This url is not acct like.'); + if (path.length <= 1) throw new Error('This url is not acct like.'); const split = path.split('@', 3); // ['', 'username', 'other.example.com'] diff --git a/packages/misskey-js/test/acct.ts b/packages/misskey-js/test/acct.ts index fd59a82c9d..510b106ad2 100644 --- a/packages/misskey-js/test/acct.ts +++ b/packages/misskey-js/test/acct.ts @@ -39,9 +39,26 @@ function testParseUrl(fn: (acct: string) => acct.Acct) { expect(res).toEqual({ username: 'alice', host: 'other.example.com' }); }); - it('throws on non-acct-like url path', () => { + it('throws on non-acct-like url path (root)', () => { + expect(() => fn('https://example.com')).toThrowError(); + }); + + it('throws on non-acct-like url path (users/alice)', () => { expect(() => fn('https://example.com/users/alice')).toThrowError(); }); + + it('throws ended with @', () => { + expect(() => fn('https://example.com/@')).toThrowError(); + }); + + it('parses url ended with /', () => { + const res = fn('https://example.com/@alice/'); + expect(res).toEqual({ username: 'alice', host: 'example.com' }); + }); + + it('throws url have @username path but ended with sub directory', () => { + expect(() => fn('https://example.com/@alice/subdir')).toThrowError(); + }); } describe('acct.parse', () => {