From fe0ace51c7b7ee124fcd69e4de1d7fc42fc11618 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Thu, 2 May 2024 16:38:37 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat(misskey-js):=20MiAuth=E8=AA=8D?= =?UTF-8?q?=E8=A8=BC=E6=A9=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/misskey-js/README.md | 38 +++++++++++++++- packages/misskey-js/etc/misskey-js.api.md | 20 +++++++++ packages/misskey-js/package.json | 12 ++--- packages/misskey-js/src/api.ts | 54 +++++++++++++++++++++++ packages/misskey-js/src/entities.ts | 5 +++ pnpm-lock.yaml | 6 +++ 6 files changed, 128 insertions(+), 7 deletions(-) diff --git a/packages/misskey-js/README.md b/packages/misskey-js/README.md index 63d4b36c56..b0ac8af9ac 100644 --- a/packages/misskey-js/README.md +++ b/packages/misskey-js/README.md @@ -37,8 +37,42 @@ import * as Misskey from 'misskey-js'; import { api as misskeyApi } from 'misskey-js'; ``` -## Authenticate -todo +## Authenticate (MiAuth) +MiAuthでの認証に対応しています。 + +### Step 1: 認証URLを生成 +`APIClient`クラスの`getMiAuthURL`メソッドを使用して認証URLを生成します(これは同期関数です)。生成したURLにユーザーを誘導し、認可させてください。 + +``` ts +const cli = new Misskey.api.APIClient({ + origin: 'https://misskey.test', +}); + +const { url } = cli.getMiAuthURL({ + name: 'My app', + callback: 'https://example.com/callback', + permission: ['read:account'], +}); + +// URLに飛ばす(例) +location.href = url; +``` + +### Step 2: セッションIDからアクセストークンを取得 +`APIClient`クラスの`authWithMiAuth`メソッドを使用してセッションIDからアクセストークンを取得します。アクセストークンは返却されるほか、以降同一のインスタンスを利用したリクエストに自動で設定されます(この挙動は第2引数に`false`を与えることで回避できます)。 + +コールバックURLを指定した場合、セッションIDはURLパラメータの`session`から取得できます。 + +``` ts +const cli = new Misskey.api.APIClient({ + origin: 'https://misskey.test', +}); + +const { token } = await cli.authWithMiAuth(sessionId); + +// 以後、同じAPIClientを使い続ける場合はトークンが自動で設定されます +const i = await cli.request('i'); +``` ## API request APIを利用する際は、利用するサーバーの情報とアクセストークンを与えて`APIClient`クラスのインスタンスを初期化し、そのインスタンスの`request`メソッドを呼び出してリクエストを行います。 diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 9720b04e39..5ca0774628 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -394,10 +394,22 @@ class APIClient { fetch?: APIClient['fetch'] | null | undefined; }); // (undocumented) + authWithMiAuth(sessionId: string, setToken?: boolean): Promise; + // (undocumented) credential: string | null | undefined; // (undocumented) fetch: FetchLike; // (undocumented) + getMiAuthURL(options: { + name?: string; + icon?: string; + callback?: string; + permission?: typeof permissions_2[number][]; + }, sessionId?: string): { + sessionId: string; + url: string; + }; + // (undocumented) origin: string; } @@ -1122,6 +1134,7 @@ declare namespace entities { SignupPendingResponse, SigninRequest, SigninResponse, + MiAuthCheckResponse, EmptyRequest, EmptyResponse, AdminMetaResponse, @@ -2248,6 +2261,12 @@ type MetaRequest = operations['meta']['requestBody']['content']['application/jso // @public (undocumented) type MetaResponse = operations['meta']['responses']['200']['content']['application/json']; +// @public (undocumented) +type MiAuthCheckResponse = { + token: string; + user: UserDetailedNotMe; +}; + // @public (undocumented) type MiauthGenTokenRequest = operations['miauth___gen-token']['requestBody']['content']['application/json']; @@ -3110,6 +3129,7 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody'][' // Warnings were encountered during analysis: // +// src/api.ts:91:3 - (ae-forgotten-export) The symbol "permissions_2" needs to be exported by the entry point index.d.ts // src/entities.ts:25:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index a9c75c95c2..2a862699e5 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -38,26 +38,28 @@ "@swc/jest": "0.2.31", "@types/jest": "29.5.12", "@types/node": "20.11.22", + "@types/uuid": "9.0.8", "@typescript-eslint/eslint-plugin": "7.1.0", "@typescript-eslint/parser": "7.1.0", + "esbuild": "0.19.11", "eslint": "8.57.0", + "execa": "8.0.1", + "glob": "10.3.10", "jest": "29.7.0", "jest-fetch-mock": "3.0.3", "jest-websocket-mock": "2.5.0", "mock-socket": "9.3.1", "ncp": "2.0.0", "nodemon": "3.1.0", - "execa": "8.0.1", "tsd": "0.30.7", - "typescript": "5.3.3", - "esbuild": "0.19.11", - "glob": "10.3.10" + "typescript": "5.3.3" }, "files": [ "built" ], "dependencies": { "eventemitter3": "5.0.1", - "reconnecting-websocket": "4.4.0" + "reconnecting-websocket": "4.4.0", + "uuid": "9.0.1" } } diff --git a/packages/misskey-js/src/api.ts b/packages/misskey-js/src/api.ts index 959a634a74..0e190460c5 100644 --- a/packages/misskey-js/src/api.ts +++ b/packages/misskey-js/src/api.ts @@ -1,7 +1,10 @@ import './autogen/apiClientJSDoc.js'; +import { v4 as uuid } from 'uuid'; import { SwitchCaseResponseType } from './api.types.js'; +import { permissions } from './consts.js'; import type { Endpoints } from './api.types.js'; +import type { MiAuthCheckResponse } from './entities.js'; export type { SwitchCaseResponseType, @@ -80,4 +83,55 @@ export class APIClient { }).catch(reject); }); } + + public getMiAuthURL(options: { + name?: string; + icon?: string; + callback?: string; + permission?: typeof permissions[number][]; + }, sessionId?: string): { + sessionId: string; + url: string; + } { + const params = new URLSearchParams(); + if (options.name) params.set('name', options.name); + if (options.icon) params.set('icon', options.icon); + if (options.callback) params.set('callback', options.callback); + if (options.permission) params.set('permission', options.permission.join(',')); + + const _sessionId = sessionId ?? uuid(); + + return { + sessionId: _sessionId, + url: `${this.origin}/miauth/${_sessionId}?${params.toString()}`, + }; + } + + public authWithMiAuth(sessionId: string, setToken = true): Promise { + return new Promise((resolve, reject) => { + this.fetch(`${this.origin}/api/miauth/${sessionId}/check`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'omit', + cache: 'no-cache', + }).then(async (res) => { + const body = res.status === 204 ? null : await res.json(); + + if (res.status === 200 && body) { + if (setToken) { + this.credential = body.token; + } + + resolve(body as MiAuthCheckResponse); + } else { + reject({ + [MK_API_ERROR]: true, + ...body.error, + }); + } + }).catch(reject); + }); + } } diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 35503d6d6f..9791e4f593 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -221,3 +221,8 @@ export type SigninResponse = { id: User['id'], i: string, }; + +export type MiAuthCheckResponse = { + token: string, + user: UserDetailedNotMe, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e5cc2d699..313eee2338 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1098,6 +1098,9 @@ importers: reconnecting-websocket: specifier: 4.4.0 version: 4.4.0 + uuid: + specifier: 9.0.1 + version: 9.0.1 devDependencies: '@microsoft/api-extractor': specifier: 7.39.1 @@ -1114,6 +1117,9 @@ importers: '@types/node': specifier: 20.11.22 version: 20.11.22 + '@types/uuid': + specifier: 9.0.8 + version: 9.0.8 '@typescript-eslint/eslint-plugin': specifier: 7.1.0 version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3) From f20695067caed4af87b91aa7cbe7dc541fd40d20 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 7 Feb 2025 20:00:30 +0900 Subject: [PATCH 2/4] docs --- packages/misskey-js/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/misskey-js/README.md b/packages/misskey-js/README.md index ed565dcf1e..cd0f21b8a3 100644 --- a/packages/misskey-js/README.md +++ b/packages/misskey-js/README.md @@ -64,6 +64,8 @@ location.href = url; コールバックURLを指定した場合、セッションIDはURLパラメータの`session`から取得できます。 ``` ts +const sessionId = new URL(location.href).searchParams.get('session'); + const cli = new Misskey.api.APIClient({ origin: 'https://misskey.test', }); From 339637c55ae634c0c118ca2775368c4608901f00 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 7 Feb 2025 20:01:20 +0900 Subject: [PATCH 3/4] Update Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 596bd62be9..2da29b4710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ ### Server - +### Misskey.js +- Feat: MiAuth 認証ラッパー ## 2025.2.0 From 5c0821ddfcf74d99412a782bc5958ecbe55d6a63 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:19:00 +0900 Subject: [PATCH 4/4] update api extractor --- packages/misskey-js/etc/misskey-js.api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 843cd8556f..51257660ea 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -3767,7 +3767,7 @@ type V2AdminEmojiListResponse = operations['v2___admin___emoji___list']['respons // Warnings were encountered during analysis: // -// src/api.ts:136:3 - (ae-forgotten-export) The symbol "permissions_2" needs to be exported by the entry point index.d.ts +// src/api.ts:135:3 - (ae-forgotten-export) The symbol "permissions_2" needs to be exported by the entry point index.d.ts // src/entities.ts:50:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.ts:57:3 - (ae-forgotten-export) The symbol "ReconnectingWebSocket" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:218:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts