mirror of
https://iceshrimp.dev/iceshrimp/iceshrimp
synced 2024-11-27 22:38:10 +09:00
wip masto api
co-authored-by: cutls <web-pro@cutls.com>
This commit is contained in:
parent
029eb6a521
commit
0756e980d1
@ -20,6 +20,7 @@
|
||||
"gulp": "gulp build",
|
||||
"watch": "pnpm run dev",
|
||||
"dev": "pnpm node ./scripts/dev.js",
|
||||
"dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start",
|
||||
"lint": "pnpm -r run lint",
|
||||
"cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts",
|
||||
"cy:run": "cypress run",
|
||||
|
@ -81,6 +81,7 @@
|
||||
"koa-send": "5.0.1",
|
||||
"koa-slow": "2.1.0",
|
||||
"koa-views": "7.0.2",
|
||||
"@cutls/megalodon": "^5.1.1",
|
||||
"mfm-js": "0.23.2",
|
||||
"mime-types": "2.1.35",
|
||||
"mocha": "10.2.0",
|
||||
|
@ -765,17 +765,17 @@ export interface IEndpointMeta {
|
||||
}
|
||||
|
||||
export interface IEndpoint {
|
||||
name: string;
|
||||
exec: any;
|
||||
meta: IEndpointMeta;
|
||||
params: Schema;
|
||||
name: string,
|
||||
exec: any, // TODO: may be obosolete @ThatOneCalculator
|
||||
meta: IEndpointMeta,
|
||||
params: Schema,
|
||||
}
|
||||
|
||||
const endpoints: IEndpoint[] = eps.map(([name, ep]) => {
|
||||
const endpoints: IEndpoint[] = (eps as [string, any]).map(([name, ep]) => {
|
||||
return {
|
||||
name: name,
|
||||
exec: ep.default,
|
||||
meta: ep.meta || {},
|
||||
meta: ep.meta ?? {},
|
||||
params: ep.paramDef,
|
||||
};
|
||||
});
|
||||
|
@ -7,6 +7,7 @@ import Router from "@koa/router";
|
||||
import multer from "@koa/multer";
|
||||
import bodyParser from "koa-bodyparser";
|
||||
import cors from "@koa/cors";
|
||||
import { apiMastodonCompatible } from './mastodon/ApiMastodonCompatibleService.js';
|
||||
import { Instances, AccessTokens, Users } from "@/models/index.js";
|
||||
import config from "@/config/index.js";
|
||||
import endpoints from "./endpoints.js";
|
||||
@ -57,6 +58,8 @@ const upload = multer({
|
||||
// Init router
|
||||
const router = new Router();
|
||||
|
||||
apiMastodonCompatible(router);
|
||||
|
||||
/**
|
||||
* Register endpoint handlers
|
||||
*/
|
||||
|
@ -0,0 +1,111 @@
|
||||
import Router from "@koa/router";
|
||||
import megalodon, { MegalodonInterface } from 'megalodon';
|
||||
|
||||
function getClient(BASE_URL: string, authorization: string | undefined): MegalodonInterface {
|
||||
const accessTokenArr = authorization?.split(' ') ?? [null];
|
||||
const accessToken = accessTokenArr[accessTokenArr.length - 1];
|
||||
const generator = (megalodon as any).default
|
||||
const client = generator('misskey', BASE_URL, accessToken) as MegalodonInterface;
|
||||
return client
|
||||
}
|
||||
const readScope = [
|
||||
'read:account',
|
||||
'read:drive',
|
||||
'read:blocks',
|
||||
'read:favorites',
|
||||
'read:following',
|
||||
'read:messaging',
|
||||
'read:mutes',
|
||||
'read:notifications',
|
||||
'read:reactions',
|
||||
'read:pages',
|
||||
'read:page-likes',
|
||||
'read:user-groups',
|
||||
'read:channels',
|
||||
'read:gallery',
|
||||
'read:gallery-likes'
|
||||
]
|
||||
const writeScope = [
|
||||
'write:account',
|
||||
'write:drive',
|
||||
'write:blocks',
|
||||
'write:favorites',
|
||||
'write:following',
|
||||
'write:messaging',
|
||||
'write:mutes',
|
||||
'write:notes',
|
||||
'write:notifications',
|
||||
'write:reactions',
|
||||
'write:votes',
|
||||
'write:pages',
|
||||
'write:page-likes',
|
||||
'write:user-groups',
|
||||
'write:channels',
|
||||
'write:gallery',
|
||||
'write:gallery-likes'
|
||||
]
|
||||
export function apiMastodonCompatible(router: Router): void {
|
||||
|
||||
router.post('/v1/apps', async (ctx) => {
|
||||
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
|
||||
const accessTokens = ctx.request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
const body: any = ctx.request.req;
|
||||
try {
|
||||
let scope = body.scopes
|
||||
if (typeof scope === 'string') scope = scope.split(' ')
|
||||
const pushScope: string[] = []
|
||||
for (const s of scope) {
|
||||
if (s.match(/^read/)) for (const r of readScope) pushScope.push(r)
|
||||
if (s.match(/^write/)) for (const r of writeScope) pushScope.push(r)
|
||||
}
|
||||
let red = body.redirect_uris
|
||||
if (red === 'urn:ietf:wg:oauth:2.0:oob') {
|
||||
red = 'https://thedesk.top/hello.html'
|
||||
}
|
||||
const appData = await client.registerApp(body.client_name, { scopes: pushScope, redirect_uris: red, website: body.website });
|
||||
ctx.body = {
|
||||
id: appData.id,
|
||||
name: appData.name,
|
||||
website: appData.website,
|
||||
redirect_uri: appData.redirectUri,
|
||||
client_id: Buffer.from(appData.url || '').toString('base64'),
|
||||
client_secret: appData.clientSecret,
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
ctx.status = 401;
|
||||
ctx.body = e.response.data;
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/v1/accounts/verify_credentials', async (ctx) => {
|
||||
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
|
||||
const accessTokens = ctx.request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
try {
|
||||
const data = await client.verifyAccountCredentials();
|
||||
ctx.body = data.data;
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
reply.code(401);
|
||||
return e.response.data;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.get('/v1/custom_emojis', async (ctx) => {
|
||||
const BASE_URL = request.protocol + '://' + request.hostname;
|
||||
const accessTokens = request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
try {
|
||||
const data = await client.getInstanceCustomEmojis();
|
||||
return data.data;
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
reply.code(401);
|
||||
return e.response.data;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
@ -20,6 +20,7 @@ import { createTemp } from "@/misc/create-temp.js";
|
||||
import { publishMainStream } from "@/services/stream.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { envOption } from "@/env.js";
|
||||
import megalodon, { MegalodonInterface } from 'megalodon';
|
||||
import activityPub from "./activitypub.js";
|
||||
import nodeinfo from "./nodeinfo.js";
|
||||
import wellKnown from "./well-known.js";
|
||||
@ -133,6 +134,26 @@ router.get("/verify-email/:code", async (ctx) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/oauth/authorize", async (ctx) => {
|
||||
const client_id = ctx.request.query.client_id;
|
||||
console.log(ctx.request.req);
|
||||
ctx.redirect(Buffer.from(client_id?.toString() || '', 'base64').toString());
|
||||
});
|
||||
|
||||
router.get("/oauth/token", async (ctx) => {
|
||||
const body: any = ctx.request.body
|
||||
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
|
||||
const generator = (megalodon as any).default;
|
||||
const client = generator('misskey', BASE_URL, null) as MegalodonInterface;
|
||||
try {
|
||||
ctx.body = await client.fetchAccessToken(null, body.client_secret, body.code);
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
ctx.status = 401;
|
||||
ctx.body = err.response.data;
|
||||
}
|
||||
});
|
||||
|
||||
// Register router
|
||||
app.use(router.routes());
|
||||
|
||||
|
@ -79,7 +79,7 @@ export default defineComponent({
|
||||
accepted() {
|
||||
this.state = 'accepted';
|
||||
if (this.session.app.callbackUrl) {
|
||||
location.href = `${this.session.app.callbackUrl}?token=${this.session.token}`;
|
||||
location.href = `${this.session.app.callbackUrl}?token=${this.session.token}&code=${this.session.token}`;
|
||||
}
|
||||
}, onLogin(res) {
|
||||
login(res.i);
|
||||
|
@ -163,6 +163,7 @@ importers:
|
||||
koa-send: 5.0.1
|
||||
koa-slow: 2.1.0
|
||||
koa-views: 7.0.2
|
||||
megalodon: ^5.1.1
|
||||
mfm-js: 0.23.2
|
||||
mime-types: 2.1.35
|
||||
mocha: 10.2.0
|
||||
@ -278,6 +279,7 @@ importers:
|
||||
koa-send: 5.0.1
|
||||
koa-slow: 2.1.0
|
||||
koa-views: 7.0.2_6tybghmia4wsnt33xeid7y4rby
|
||||
megalodon: 5.1.1
|
||||
mfm-js: 0.23.2
|
||||
mime-types: 2.1.35
|
||||
mocha: 10.2.0
|
||||
@ -2348,7 +2350,6 @@ packages:
|
||||
resolution: {integrity: sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==}
|
||||
dependencies:
|
||||
'@types/node': 18.11.18
|
||||
dev: true
|
||||
|
||||
/@types/offscreencanvas/2019.3.0:
|
||||
resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
|
||||
@ -2529,6 +2530,12 @@ packages:
|
||||
'@types/node': 18.11.18
|
||||
dev: true
|
||||
|
||||
/@types/ws/8.5.4:
|
||||
resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==}
|
||||
dependencies:
|
||||
'@types/node': 18.11.18
|
||||
dev: false
|
||||
|
||||
/@types/yauzl/2.10.0:
|
||||
resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
|
||||
requiresBuild: true
|
||||
@ -3246,7 +3253,7 @@ packages:
|
||||
/axios/0.24.0:
|
||||
resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2
|
||||
follow-redirects: 1.15.2_debug@4.3.4
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
@ -3254,11 +3261,21 @@ packages:
|
||||
/axios/0.25.0_debug@4.3.4:
|
||||
resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2
|
||||
follow-redirects: 1.15.2_debug@4.3.4
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: true
|
||||
|
||||
/axios/1.2.2:
|
||||
resolution: {integrity: sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2_debug@4.3.4
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/babel-eslint/10.1.0_eslint@8.31.0:
|
||||
resolution: {integrity: sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==}
|
||||
engines: {node: '>=6'}
|
||||
@ -4940,7 +4957,6 @@ packages:
|
||||
|
||||
/dayjs/1.11.7:
|
||||
resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==}
|
||||
dev: true
|
||||
|
||||
/debug/2.6.9:
|
||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||
@ -6197,7 +6213,7 @@ packages:
|
||||
readable-stream: 2.3.7
|
||||
dev: false
|
||||
|
||||
/follow-redirects/1.15.2:
|
||||
/follow-redirects/1.15.2_debug@4.3.4:
|
||||
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
@ -6205,6 +6221,8 @@ packages:
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
|
||||
/for-each/0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
@ -8654,6 +8672,30 @@ packages:
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/megalodon/5.1.1:
|
||||
resolution: {integrity: sha512-zsYzzmogmk9lnXzGk3kKv58LUmZVFMebiya/1CZqZYnBVxq18Ep8l1AU41o+INANMqYxG+hAQvJhE+Z5dcUabQ==}
|
||||
engines: {node: '>=15.0.0'}
|
||||
dependencies:
|
||||
'@types/oauth': 0.9.1
|
||||
'@types/ws': 8.5.4
|
||||
axios: 1.2.2
|
||||
dayjs: 1.11.7
|
||||
form-data: 4.0.0
|
||||
https-proxy-agent: 5.0.1
|
||||
oauth: 0.10.0
|
||||
object-assign-deep: 0.4.0
|
||||
parse-link-header: 2.0.0
|
||||
socks-proxy-agent: 7.0.0
|
||||
typescript: 4.9.4
|
||||
uuid: 9.0.0
|
||||
ws: 8.12.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/merge-stream/2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
|
||||
@ -9321,6 +9363,11 @@ packages:
|
||||
resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==}
|
||||
dev: false
|
||||
|
||||
/object-assign-deep/0.4.0:
|
||||
resolution: {integrity: sha512-54Uvn3s+4A/cMWx9tlRez1qtc7pN7pbQ+Yi7mjLjcBpWLlP+XbSHiHbQW6CElDiV4OvuzqnMrBdkgxI1mT8V/Q==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/object-assign/4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -9613,6 +9660,12 @@ packages:
|
||||
error-ex: 1.3.2
|
||||
dev: false
|
||||
|
||||
/parse-link-header/2.0.0:
|
||||
resolution: {integrity: sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==}
|
||||
dependencies:
|
||||
xtend: 4.0.2
|
||||
dev: false
|
||||
|
||||
/parse-node-version/1.0.1:
|
||||
resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
|
||||
engines: {node: '>= 0.10'}
|
||||
@ -10254,6 +10307,10 @@ packages:
|
||||
resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==}
|
||||
dev: true
|
||||
|
||||
/proxy-from-env/1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
dev: false
|
||||
|
||||
/ps-tree/1.2.0:
|
||||
resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==}
|
||||
engines: {node: '>= 0.10'}
|
||||
@ -12943,6 +13000,19 @@ packages:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/ws/8.12.0:
|
||||
resolution: {integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/xev/3.0.2:
|
||||
resolution: {integrity: sha512-8kxuH95iMXzHZj+fwqfA4UrPcYOy6bGIgfWzo9Ji23JoEc30ge/Z++Ubkiuy8c0+M64nXmmxrmJ7C8wnuBhluw==}
|
||||
dev: false
|
||||
|
Loading…
Reference in New Issue
Block a user