diff --git a/migration/1599570288522-mypage.ts b/migration/1599570288522-mypage.ts new file mode 100644 index 0000000..b0ce493 --- /dev/null +++ b/migration/1599570288522-mypage.ts @@ -0,0 +1,18 @@ +import {MigrationInterface, QueryRunner} from 'typeorm'; + +export class mypage1599570288522 implements MigrationInterface { + name = 'mypage1599570288522' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "used_token" ("token" character varying NOT NULL, CONSTRAINT "PK_7f2db4c33c33cd6b38e63393fe5" PRIMARY KEY ("token"))'); + await queryRunner.query('CREATE UNIQUE INDEX "IDX_7f2db4c33c33cd6b38e63393fe" ON "used_token" ("token") '); + await queryRunner.query('ALTER TABLE "user" ADD "misshaiToken" character varying NOT NULL DEFAULT \'\''); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "user" DROP COLUMN "misshaiToken"'); + await queryRunner.query('DROP INDEX "IDX_7f2db4c33c33cd6b38e63393fe"'); + await queryRunner.query('DROP TABLE "used_token"'); + } + +} diff --git a/ormconfig.js b/ormconfig.js index 2c1af23..caa751d 100644 --- a/ormconfig.js +++ b/ormconfig.js @@ -1,6 +1,6 @@ const fs = require('fs'); -const entities = require('./built/db').entities; +const entities = require('./built/services/db').entities; const config = Object.freeze(JSON.parse(fs.readFileSync(__dirname + '/config.json', 'utf-8'))); diff --git a/src/app.ts b/src/app.ts index d74458a..f7f3319 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,4 +1,5 @@ import { initDb } from './services/db'; +import 'reflect-metadata'; (async () => { await initDb(); diff --git a/src/functions/gen-token.ts b/src/functions/gen-token.ts new file mode 100644 index 0000000..af520f2 --- /dev/null +++ b/src/functions/gen-token.ts @@ -0,0 +1,13 @@ +import rndstr from 'rndstr'; +import { UsedToken } from '../models/entities/usedToken'; +import { UsedTokens } from '../models'; + +export const genToken = async (): Promise => { + let used: UsedToken | undefined = undefined; + let token: string; + do { + token = rndstr(32); + used = await UsedTokens.findOne({ token }); + } while (used !== undefined); + return token; +}; \ No newline at end of file diff --git a/src/functions/users.ts b/src/functions/users.ts index 0bc8f0b..169aff2 100644 --- a/src/functions/users.ts +++ b/src/functions/users.ts @@ -1,15 +1,30 @@ import { User } from '../models/entities/user'; import { Users } from '../models'; import { DeepPartial } from 'typeorm'; +import { genToken } from './gen-token'; export const getUser = (username: string, host: string): Promise => { return Users.findOne({ username, host }); }; +export const updateUsersMisshaiToken = async (user: User | User['id']): Promise => { + const u = typeof user === 'number' + ? user + : user.id; + + const misshaiToken = await genToken(); + Users.update(u, { misshaiToken }); + return misshaiToken; +}; + +export const getUserByMisshaiToken = (token: string): Promise => { + return Users.findOne({ misshaiToken: token }); +}; + export const upsertUser = async (username: string, host: string, token: string): Promise => { const u = await getUser(username, host); if (u) { - await Users.update({ username, host }, { token }); + await Users.update(u.id, { token }); } else { await Users.insert({ username, host, token }); } diff --git a/src/models/entities/usedToken.ts b/src/models/entities/usedToken.ts new file mode 100644 index 0000000..17ede3c --- /dev/null +++ b/src/models/entities/usedToken.ts @@ -0,0 +1,10 @@ +import { Entity, Index, PrimaryColumn } from 'typeorm'; + +@Entity() +@Index([ 'token' ], { unique: true }) +export class UsedToken { + @PrimaryColumn({ + type: 'varchar' + }) + public token: string; +} \ No newline at end of file diff --git a/src/models/entities/user.ts b/src/models/entities/user.ts index fa0faaa..2feea18 100644 --- a/src/models/entities/user.ts +++ b/src/models/entities/user.ts @@ -21,6 +21,12 @@ export class User { }) public token: string; + @Column({ + type: 'varchar', + default: '' + }) + public misshaiToken: string; + @Column({ type: 'integer', default: 0, diff --git a/src/models/index.ts b/src/models/index.ts index 3aa06c2..2fa6915 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,4 +1,6 @@ import { User } from './entities/user'; +import { UsedToken } from './entities/usedToken'; import { getRepository } from 'typeorm'; -export const Users = getRepository(User); \ No newline at end of file +export const Users = getRepository(User); +export const UsedTokens = getRepository(UsedToken); \ No newline at end of file diff --git a/src/models/repositories/.gitkeep b/src/models/repositories/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/server/render.ts b/src/server/render.ts index 90e00a7..5a3ad50 100644 --- a/src/server/render.ts +++ b/src/server/render.ts @@ -3,7 +3,7 @@ import views from 'koa-views'; import constant from '../const'; -export const render = views(__dirname + '/views', { +export const render = views(__dirname + '/../views', { extension: 'pug', options: { ...constant, } diff --git a/src/server/router.ts b/src/server/router.ts index a72c3b7..4cd99e2 100644 --- a/src/server/router.ts +++ b/src/server/router.ts @@ -6,22 +6,13 @@ import crypto from 'crypto'; import { die } from './die'; import { v4 as uuid } from 'uuid'; import { config } from '../config'; -import { upsertUser, getUser, getUserCount, updateUser } from '../functions/users'; +import { upsertUser, getUser, getUserCount, updateUser, updateUsersMisshaiToken, getUserByMisshaiToken } from '../functions/users'; import { api } from '../services/misskey'; export const router = new Router(); const sessionHostCache: Record = { }; const tokenSecretCache: Record = { }; -const ipAccessCount: Record = {}; - -const freshIpAccessCount = (time: number) => { - for (const ips of Object.keys(ipAccessCount)) { - if (time - ipAccessCount[ips].time > 2000) { - delete ipAccessCount[ips]; - } - } -}; const welcomeMessage = [ 'ついついノートしすぎていませんか?', @@ -32,16 +23,9 @@ const welcomeMessage = [ 'あなたは真の Misskey 廃人ですか?' ]; -const scoldingMessage = [ - 'さてはリロードを繰り返しているな?', - '何パターンあるか調べようとしてることはバレてんだぞ', - '何度もリロードして楽しいかい?', - 'はいはいわかったから早うログインしな!', - '君には他にやるべきことがあるんじゃないか?', -]; - const login = async (ctx: Context, user: Record, host: string, token: string) => { await upsertUser(user.username as string, host, token); + const u = await getUser(user.username as string, host); if (!u) { @@ -55,21 +39,28 @@ const login = async (ctx: Context, user: Record, host: string, prevFollowersCount: user.followersCount as number, }); - await ctx.render('logined', { user: u }); + const misshaiToken = await updateUsersMisshaiToken(u); + + ctx.cookies.set('token', misshaiToken, { signed: true }); + + // await ctx.render('logined', { user: u }); + ctx.redirect('/'); }; router.get('/', async ctx => { - const time = new Date().getTime(); - freshIpAccessCount(time); - if (!ipAccessCount[ctx.ip]) { - ipAccessCount[ctx.ip] = { count: 0, time }; + const token = ctx.cookies.get('token', { signed: true }); + const user = token ? await getUserByMisshaiToken(token) : undefined; + if (!user) { + // 非ログイン + await ctx.render('welcome', { + usersCount: await getUserCount(), + welcomeMessage: welcomeMessage[Math.floor(Math.random() * welcomeMessage.length)], + }); } else { - ipAccessCount[ctx.ip] = { count: ipAccessCount[ctx.ip].count + 1, time }; + await ctx.render('mypage', { + user + }); } - await ctx.render('welcome', { - usersCount: await getUserCount(), - welcomeMessage: ipAccessCount[ctx.ip].count > 5 ? scoldingMessage[Math.floor(Math.random() * scoldingMessage.length)] : welcomeMessage[Math.floor(Math.random() * welcomeMessage.length)], - }); }); router.get('/login', async ctx => { diff --git a/src/server/server.ts b/src/server/server.ts index f4bd7b0..fde269c 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -20,9 +20,11 @@ export default (): void => { app.use(bodyParser()); app.use(render); - app.use(mount('/assets', serve(__dirname + '/assets'))); + app.use(mount('/assets', serve(__dirname + '/../assets'))); app.use(router.routes()); + app.keys = [ '人類', 'ミス廃化', '計画', 'ここに極まれり', 'フッフッフ...' ]; + console.log(`listening port ${config.port}...`); console.log('App launched!'); diff --git a/src/services/db.ts b/src/services/db.ts index a7e106f..4cfc7c8 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -1,9 +1,11 @@ import { getConnection, createConnection, Connection } from 'typeorm'; import { config } from '../config'; import { User } from '../models/entities/user'; +import { UsedToken } from '../models/entities/usedToken'; export const entities = [ - User + User, + UsedToken, ]; export const initDb = async (force = false): Promise => { diff --git a/src/views/logined.pug b/src/views/logined.pug deleted file mode 100644 index 398e852..0000000 --- a/src/views/logined.pug +++ /dev/null @@ -1,6 +0,0 @@ -extends _base - -block content - section - h2 おかえりなさい、@!{ user.username }@!{ user.host } さん。 - p みす廃あらーとの設定は完了しています。Have a good Misskey 👍 \ No newline at end of file diff --git a/src/views/mypage.pug b/src/views/mypage.pug new file mode 100644 index 0000000..12eb744 --- /dev/null +++ b/src/views/mypage.pug @@ -0,0 +1,6 @@ +extends _base + +block content + section + h2 マイページ + p おかえりなさい、@!{ user.username }@!{ user.host } さん。 \ No newline at end of file