resolve #3
This commit is contained in:
parent
405a738a3c
commit
3a4bcee3f4
2 changed files with 80 additions and 30 deletions
|
@ -7,7 +7,7 @@ axios.defaults.headers['User-Agent'] = ua;
|
||||||
|
|
||||||
axios.defaults.validateStatus = (stat) => stat < 500;
|
axios.defaults.validateStatus = (stat) => stat < 500;
|
||||||
|
|
||||||
export const api = <T>(host: string, endpoint: string, arg: Record<string, unknown>, i?: string): Promise<T> => {
|
export const api = <T = Record<string, unknown>>(host: string, endpoint: string, arg: Record<string, unknown>, i?: string): Promise<T> => {
|
||||||
const a = { ...arg };
|
const a = { ...arg };
|
||||||
if (i) {
|
if (i) {
|
||||||
a.i = i;
|
a.i = i;
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
import { Context, DefaultState } from 'koa';
|
import { Context, DefaultState } from 'koa';
|
||||||
import Router from 'koa-router';
|
import Router from 'koa-router';
|
||||||
|
import axios from 'axios';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
import { die } from './die';
|
import { die } from './die';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { config } from './config';
|
import { config } from './config';
|
||||||
import axios from 'axios';
|
|
||||||
import { upsertUser, getUser, getUserCount, updateUser } from './users';
|
import { upsertUser, getUser, getUserCount, updateUser } from './users';
|
||||||
import { api } from './misskey';
|
import { api } from './misskey';
|
||||||
|
|
||||||
export const router = new Router<DefaultState, Context>();
|
export const router = new Router<DefaultState, Context>();
|
||||||
|
|
||||||
const sessionHostCache: Record<string, string> = { };
|
const sessionHostCache: Record<string, string> = { };
|
||||||
|
const tokenSecretCache: Record<string, string> = { };
|
||||||
const ipAccessCount: Record<string, { time: number, count: number }> = {};
|
const ipAccessCount: Record<string, { time: number, count: number }> = {};
|
||||||
|
|
||||||
const freshIpAccessCount = (time: number) => {
|
const freshIpAccessCount = (time: number) => {
|
||||||
|
@ -37,6 +40,24 @@ const scoldingMessage = [
|
||||||
'君には他にやるべきことがあるんじゃないか?',
|
'君には他にやるべきことがあるんじゃないか?',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const login = async (ctx: Context, user: Record<string, unknown>, host: string, token: string) => {
|
||||||
|
await upsertUser(user.username as string, host, token);
|
||||||
|
const u = await getUser(user.username as string, host);
|
||||||
|
|
||||||
|
if (!u) {
|
||||||
|
await die(ctx, '問題が発生しました。お手数ですが、最初からやり直してください。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateUser(u.username, u.host, {
|
||||||
|
prevNotesCount: user.notesCount as number,
|
||||||
|
prevFollowingCount: user.followingCount as number,
|
||||||
|
prevFollowersCount: user.followersCount as number,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ctx.render('logined', { user: u });
|
||||||
|
};
|
||||||
|
|
||||||
router.get('/', async ctx => {
|
router.get('/', async ctx => {
|
||||||
const time = new Date().getTime();
|
const time = new Date().getTime();
|
||||||
freshIpAccessCount(time);
|
freshIpAccessCount(time);
|
||||||
|
@ -53,30 +74,45 @@ router.get('/', async ctx => {
|
||||||
|
|
||||||
router.get('/login', async ctx => {
|
router.get('/login', async ctx => {
|
||||||
let host = ctx.query.host as string | undefined;
|
let host = ctx.query.host as string | undefined;
|
||||||
ctx.mac;
|
|
||||||
if (!host) {
|
if (!host) {
|
||||||
await die(ctx, 'ホストを空欄にしてはいけない');
|
await die(ctx, 'ホストを空欄にしてはいけない');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const meta = await api<{ name: string, uri: string, features: Record<string, boolean | undefined> }>(host, 'meta', {});
|
const meta = await api<{ name: string, uri: string, features: Record<string, boolean | undefined> }>(host, 'meta', {});
|
||||||
|
|
||||||
// MiAuth 以外はサポートしていない
|
|
||||||
if (!meta.features.miauth) {
|
|
||||||
await die(ctx, 'ごめんなさい。お使いのインスタンス "' + (meta.name || host) + '" はまだサポートされていません。現在、MiAuth 認証方式をサポートするバージョンの Misskey のみご利用頂けます。対象の Misskey バージョンは Misskey v12, Groundpolis v3 の最新版です。インスタンス管理者にご問い合わせください。');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ホスト名の正規化
|
// ホスト名の正規化
|
||||||
host = meta.uri.replace(/^https?:\/\//, '');
|
host = meta.uri.replace(/^https?:\/\//, '');
|
||||||
|
const name = 'みす廃あらーと';
|
||||||
|
const description = 'ついついノートしすぎていませんか?';
|
||||||
|
const permission = [ 'write:notes' ];
|
||||||
|
|
||||||
|
if (meta.features.miauth) {
|
||||||
|
// Use MiAuth
|
||||||
|
const callback = encodeURI(`${config.url}/miauth`);
|
||||||
|
|
||||||
const session = uuid();
|
const session = uuid();
|
||||||
const name = encodeURI('みす廃あらーと');
|
const url = `https://${host}/miauth/${session}?name=${encodeURI(name)}&callback=${encodeURI(callback)}&permission=${encodeURI(permission.join(','))}`;
|
||||||
const permission = encodeURI('write:notes');
|
|
||||||
const callback = encodeURI(`${config.url}/miauth`);
|
|
||||||
const url = `https://${host}/miauth/${session}?name=${name}&callback=${callback}&permission=${permission}`;
|
|
||||||
sessionHostCache[session] = host;
|
sessionHostCache[session] = host;
|
||||||
|
|
||||||
ctx.redirect(url);
|
ctx.redirect(url);
|
||||||
|
} else {
|
||||||
|
// Use legacy authentication
|
||||||
|
const callbackUrl = encodeURI(`${config.url}/legacy-auth`);
|
||||||
|
|
||||||
|
const { secret } = await api<{ secret: string }>(host, 'app/create', {
|
||||||
|
name, description, permission, callbackUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { token, url } = await api<{ token: string, url: string }>(host, 'auth/session/generate', {
|
||||||
|
appSecret: secret
|
||||||
|
});
|
||||||
|
|
||||||
|
sessionHostCache[token] = host;
|
||||||
|
tokenSecretCache[token] = secret;
|
||||||
|
|
||||||
|
ctx.redirect(url);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/terms', async ctx => {
|
router.get('/terms', async ctx => {
|
||||||
|
@ -94,14 +130,16 @@ router.get('/teapot', async ctx => {
|
||||||
router.get('/miauth', async ctx => {
|
router.get('/miauth', async ctx => {
|
||||||
const session = ctx.query.session as string | undefined;
|
const session = ctx.query.session as string | undefined;
|
||||||
if (!session) {
|
if (!session) {
|
||||||
await die(ctx, 'セッションが見つからなかった');
|
await die(ctx, 'session required');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const host = sessionHostCache[session];
|
const host = sessionHostCache[session];
|
||||||
|
delete sessionHostCache[session];
|
||||||
if (!host) {
|
if (!host) {
|
||||||
await die(ctx, '問題が発生しました。お手数ですが、最初からやり直してください。');
|
await die(ctx, '問題が発生しました。お手数ですが、最初からやり直してください。');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `https://${host}/api/miauth/${session}/check`;
|
const url = `https://${host}/api/miauth/${session}/check`;
|
||||||
const { token, user } = (await axios.post(url)).data;
|
const { token, user } = (await axios.post(url)).data;
|
||||||
|
|
||||||
|
@ -110,25 +148,37 @@ router.get('/miauth', async ctx => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await upsertUser(user.username, host, token);
|
await login(ctx, user, host, token);
|
||||||
const u = await getUser(user.username, host);
|
|
||||||
|
|
||||||
if (!u) {
|
});
|
||||||
|
|
||||||
|
router.get('/legacy-auth', async ctx => {
|
||||||
|
const token = ctx.query.token as string | undefined;
|
||||||
|
if (!token) {
|
||||||
|
await die(ctx, 'token required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const host = sessionHostCache[token];
|
||||||
|
delete sessionHostCache[token];
|
||||||
|
if (!host) {
|
||||||
|
await die(ctx, '問題が発生しました。お手数ですが、最初からやり直してください。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const appSecret = tokenSecretCache[token];
|
||||||
|
delete tokenSecretCache[token];
|
||||||
|
if (!appSecret) {
|
||||||
await die(ctx, '問題が発生しました。お手数ですが、最初からやり直してください。');
|
await die(ctx, '問題が発生しました。お手数ですが、最初からやり直してください。');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateUser(u.username, u.host, {
|
console.log(host);
|
||||||
prevNotesCount: user.notesCount,
|
|
||||||
prevFollowingCount: user.followingCount,
|
|
||||||
prevFollowersCount: user.followersCount,
|
|
||||||
});
|
|
||||||
|
|
||||||
await ctx.render('logined', { user: u });
|
const { accessToken, user } = await api<{ accessToken: string, user: Record<string, unknown> }>(host, 'auth/session/userkey', {
|
||||||
|
appSecret, token,
|
||||||
});
|
});
|
||||||
|
const i = crypto.createHash('sha256').update(accessToken + appSecret, 'utf8').digest('hex');
|
||||||
|
|
||||||
router.get('/legacy-auth', async ctx => {
|
await login(ctx, user, host, i);
|
||||||
await die(ctx, 'coming soon');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue