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', () => {