[mastodon-client] POST /apps
This commit is contained in:
parent
5e20c3ae06
commit
f57239fc58
3 changed files with 171 additions and 14 deletions
|
|
@ -1,8 +1,6 @@
|
||||||
import megalodon, { MegalodonInterface } from "megalodon";
|
|
||||||
import Router from "@koa/router";
|
import Router from "@koa/router";
|
||||||
import { koaBody } from "koa-body";
|
import { AuthHelpers } from "@/server/api/mastodon/helpers/auth.js";
|
||||||
import { getClient } from "../ApiMastodonCompatibleService.js";
|
import { convertId, IdType } from "@/misc/convert-id.js";
|
||||||
import bodyParser from "koa-bodyparser";
|
|
||||||
|
|
||||||
const readScope = [
|
const readScope = [
|
||||||
"read:account",
|
"read:account",
|
||||||
|
|
@ -43,8 +41,6 @@ const writeScope = [
|
||||||
|
|
||||||
export function apiAuthMastodon(router: Router): void {
|
export function apiAuthMastodon(router: Router): void {
|
||||||
router.post("/v1/apps", async (ctx) => {
|
router.post("/v1/apps", async (ctx) => {
|
||||||
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
|
|
||||||
const client = getClient(BASE_URL, "");
|
|
||||||
const body: any = ctx.request.body || ctx.request.query;
|
const body: any = ctx.request.body || ctx.request.query;
|
||||||
try {
|
try {
|
||||||
let scope = body.scopes;
|
let scope = body.scopes;
|
||||||
|
|
@ -57,20 +53,15 @@ export function apiAuthMastodon(router: Router): void {
|
||||||
const scopeArr = Array.from(pushScope);
|
const scopeArr = Array.from(pushScope);
|
||||||
|
|
||||||
const red = body.redirect_uris;
|
const red = body.redirect_uris;
|
||||||
const appData = await client.registerApp(body.client_name, {
|
const appData = await AuthHelpers.registerApp(body['client_name'], scopeArr, red, body['website']);
|
||||||
scopes: scopeArr,
|
|
||||||
redirect_uris: red,
|
|
||||||
website: body.website,
|
|
||||||
});
|
|
||||||
const returns = {
|
const returns = {
|
||||||
id: Math.floor(Math.random() * 100).toString(),
|
id: convertId(appData.id, IdType.MastodonId),
|
||||||
name: appData.name,
|
name: appData.name,
|
||||||
website: body.website,
|
website: body.website,
|
||||||
redirect_uri: red,
|
redirect_uri: red,
|
||||||
client_id: Buffer.from(appData.url || "").toString("base64"),
|
client_id: Buffer.from(appData.url ?? "").toString("base64"),
|
||||||
client_secret: appData.clientSecret,
|
client_secret: appData.clientSecret,
|
||||||
};
|
};
|
||||||
console.log(returns);
|
|
||||||
ctx.body = returns;
|
ctx.body = returns;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
|
||||||
123
packages/backend/src/server/api/mastodon/entities/oauth/oauth.ts
Normal file
123
packages/backend/src/server/api/mastodon/entities/oauth/oauth.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* OAuth
|
||||||
|
* Response data when oauth request.
|
||||||
|
**/
|
||||||
|
namespace OAuth {
|
||||||
|
export type AppDataFromServer = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
website: string | null;
|
||||||
|
redirect_uri: string;
|
||||||
|
client_id: string;
|
||||||
|
client_secret: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TokenDataFromServer = {
|
||||||
|
access_token: string;
|
||||||
|
token_type: string;
|
||||||
|
scope: string;
|
||||||
|
created_at: number;
|
||||||
|
expires_in: number | null;
|
||||||
|
refresh_token: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class AppData {
|
||||||
|
public url: string | null;
|
||||||
|
public session_token: string | null;
|
||||||
|
constructor(
|
||||||
|
public id: string,
|
||||||
|
public name: string,
|
||||||
|
public website: string | null,
|
||||||
|
public redirect_uri: string,
|
||||||
|
public client_id: string,
|
||||||
|
public client_secret: string,
|
||||||
|
) {
|
||||||
|
this.url = null;
|
||||||
|
this.session_token = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize raw application data from server
|
||||||
|
* @param raw from server
|
||||||
|
*/
|
||||||
|
static from(raw: AppDataFromServer) {
|
||||||
|
return new this(
|
||||||
|
raw.id,
|
||||||
|
raw.name,
|
||||||
|
raw.website,
|
||||||
|
raw.redirect_uri,
|
||||||
|
raw.client_id,
|
||||||
|
raw.client_secret,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get redirectUri() {
|
||||||
|
return this.redirect_uri;
|
||||||
|
}
|
||||||
|
get clientId() {
|
||||||
|
return this.client_id;
|
||||||
|
}
|
||||||
|
get clientSecret() {
|
||||||
|
return this.client_secret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TokenData {
|
||||||
|
public _scope: string;
|
||||||
|
constructor(
|
||||||
|
public access_token: string,
|
||||||
|
public token_type: string,
|
||||||
|
scope: string,
|
||||||
|
public created_at: number,
|
||||||
|
public expires_in: number | null = null,
|
||||||
|
public refresh_token: string | null = null,
|
||||||
|
) {
|
||||||
|
this._scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize raw token data from server
|
||||||
|
* @param raw from server
|
||||||
|
*/
|
||||||
|
static from(raw: TokenDataFromServer) {
|
||||||
|
return new this(
|
||||||
|
raw.access_token,
|
||||||
|
raw.token_type,
|
||||||
|
raw.scope,
|
||||||
|
raw.created_at,
|
||||||
|
raw.expires_in,
|
||||||
|
raw.refresh_token,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth Aceess Token
|
||||||
|
*/
|
||||||
|
get accessToken() {
|
||||||
|
return this.access_token;
|
||||||
|
}
|
||||||
|
get tokenType() {
|
||||||
|
return this.token_type;
|
||||||
|
}
|
||||||
|
get scope() {
|
||||||
|
return this._scope;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Application ID
|
||||||
|
*/
|
||||||
|
get createdAt() {
|
||||||
|
return this.created_at;
|
||||||
|
}
|
||||||
|
get expiresIn() {
|
||||||
|
return this.expires_in;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* OAuth Refresh Token
|
||||||
|
*/
|
||||||
|
get refreshToken() {
|
||||||
|
return this.refresh_token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OAuth;
|
||||||
43
packages/backend/src/server/api/mastodon/helpers/auth.ts
Normal file
43
packages/backend/src/server/api/mastodon/helpers/auth.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import OAuth from "@/server/api/mastodon/entities/oauth/oauth.js";
|
||||||
|
import { secureRndstr } from "@/misc/secure-rndstr.js";
|
||||||
|
import { Apps, AuthSessions } from "@/models/index.js";
|
||||||
|
import { genId } from "@/misc/gen-id.js";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
|
import config from "@/config/index.js";
|
||||||
|
|
||||||
|
export class AuthHelpers {
|
||||||
|
public static async registerApp(name: string, scopes: string[], redirect_uris: string, website: string | null): Promise<OAuth.AppData> {
|
||||||
|
const secret = secureRndstr(32);
|
||||||
|
const app = await Apps.insert({
|
||||||
|
id: genId(),
|
||||||
|
createdAt: new Date(),
|
||||||
|
userId: null,
|
||||||
|
name: name,
|
||||||
|
description: '',
|
||||||
|
permission: scopes,
|
||||||
|
callbackUrl: redirect_uris,
|
||||||
|
secret: secret,
|
||||||
|
}).then((x) => Apps.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
|
const appdataPre: OAuth.AppDataFromServer = {
|
||||||
|
id: app.id,
|
||||||
|
name: app.name,
|
||||||
|
website: website,
|
||||||
|
client_id: "",
|
||||||
|
client_secret: app.secret,
|
||||||
|
redirect_uri: redirect_uris!
|
||||||
|
}
|
||||||
|
const appdata = OAuth.AppData.from(appdataPre);
|
||||||
|
const token = uuid();
|
||||||
|
const session = await AuthSessions.insert({
|
||||||
|
id: genId(),
|
||||||
|
createdAt: new Date(),
|
||||||
|
appId: app.id,
|
||||||
|
token: token,
|
||||||
|
}).then((x) => AuthSessions.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
|
appdata.url = `${config.authUrl}/${session.token}`;
|
||||||
|
appdata.session_token = session.token;
|
||||||
|
return appdata;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue