From ac9dc00c6a0eaa488b3a4c934d94181997fd8943 Mon Sep 17 00:00:00 2001 From: undefined Date: Wed, 12 Aug 2020 00:31:59 +0800 Subject: [PATCH] +login-with-qq --- packages/hydrooj/package.json | 2 +- packages/hydrooj/src/handler/user.ts | 2 +- packages/hydrooj/src/loader.ts | 1 + packages/hydrooj/src/model/token.ts | 4 ++- packages/login-with-qq/README.md | 1 + packages/login-with-qq/lib.ts | 36 +++++++++++++++++++++++ packages/login-with-qq/locales/zh_CN.yaml | 1 + packages/login-with-qq/package.json | 19 ++++++++++++ packages/login-with-qq/service.ts | 35 ++++++++++++++++++++++ packages/login-with-qq/setting.yaml | 15 ++++++++++ packages/login-with-qq/tsconfig.json | 19 ++++++++++++ tsconfig.json | 1 + 12 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 packages/login-with-qq/README.md create mode 100644 packages/login-with-qq/lib.ts create mode 100644 packages/login-with-qq/locales/zh_CN.yaml create mode 100644 packages/login-with-qq/package.json create mode 100644 packages/login-with-qq/service.ts create mode 100644 packages/login-with-qq/setting.yaml create mode 100644 packages/login-with-qq/tsconfig.json diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 90b416862..9da680eb8 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.12.13", + "version": "2.12.14", "bin": "bin/hydrooj.js", "main": "dist/loader.js", "typings": "dist/loader.d.ts", diff --git a/packages/hydrooj/src/handler/user.ts b/packages/hydrooj/src/handler/user.ts index 8d1833507..5be8b8e27 100644 --- a/packages/hydrooj/src/handler/user.ts +++ b/packages/hydrooj/src/handler/user.ts @@ -225,7 +225,7 @@ class OauthHandler extends Handler { class OauthCallbackHandler extends Handler { async get(args: any) { let r; - if (global.Hydro.lib[`oauth_${args.type}`]) r = await global.Hydro.lib[`oauth_${args.type}`].callback(args); + if (global.Hydro.lib[`oauth_${args.type}`]) r = await global.Hydro.lib[`oauth_${args.type}`].callback.call(this, args); else throw new UserFacingError('Oauth type'); const udoc = await user.getByEmail('system', r.email); if (udoc) { diff --git a/packages/hydrooj/src/loader.ts b/packages/hydrooj/src/loader.ts index f6525a827..507b584bd 100644 --- a/packages/hydrooj/src/loader.ts +++ b/packages/hydrooj/src/loader.ts @@ -9,6 +9,7 @@ import cluster from 'cluster'; import fs from 'fs-extra'; import { argv } from 'yargs'; import AdmZip from 'adm-zip'; +import { } from './utils'; export * from './interface'; diff --git a/packages/hydrooj/src/model/token.ts b/packages/hydrooj/src/model/token.ts index 6010afb7d..ef7342edf 100644 --- a/packages/hydrooj/src/model/token.ts +++ b/packages/hydrooj/src/model/token.ts @@ -2,7 +2,7 @@ import { Collection } from 'mongodb'; import { TokenDoc } from '../interface'; import * as db from '../service/db'; -const coll: Collection = db.collection('token'); +export const coll: Collection = db.collection('token'); export const TYPE_SESSION = 0; export const TYPE_REGISTRATION = 2; @@ -88,6 +88,8 @@ export function delByUid(uid: number) { global.Hydro.postInit.push(ensureIndexes); global.Hydro.model.token = { + coll, + TYPE_SESSION, TYPE_CHANGEMAIL, TYPE_OAUTH, diff --git a/packages/login-with-qq/README.md b/packages/login-with-qq/README.md new file mode 100644 index 000000000..9cf59d171 --- /dev/null +++ b/packages/login-with-qq/README.md @@ -0,0 +1 @@ +# Login-With-QQ diff --git a/packages/login-with-qq/lib.ts b/packages/login-with-qq/lib.ts new file mode 100644 index 000000000..2c2b72e6f --- /dev/null +++ b/packages/login-with-qq/lib.ts @@ -0,0 +1,36 @@ +import 'hydrooj'; +import 'hydrooj/dist/utils'; + +async function get() { + const { system, token } = global.Hydro.model; + const secret = String.random(8); + const [id, [tokenId]] = await Promise.all([ + system.get('login-with-qq.id'), + token.add(token.TYPE_OAUTH, 600, { redirect: this.request.referer, secret }), + ]); + const message = `Please send "login ${secret}" to qq account ${id}, and then use the link below:\n /oauth/qq/callback?state=${tokenId}`; + this.response.body = { + code: tokenId, secret, id, message, + }; +} + +async function callback({ state }) { + const { token } = global.Hydro.model; + const { InvalidTokenError } = global.Hydro.error; + const s = await token.get(state, token.TYPE_OAUTH); + if (!s || !s.email) throw new InvalidTokenError(state); + const ret = { + email: s.email, + bio: '', + uname: [s.username], + }; + this.response.redirect = s.redirect; + await token.del(s._id, token.TYPE_OAUTH); + return ret; +} + +global.Hydro.lib.oauth_qq = { + text: 'Login with QQ', + callback, + get, +}; diff --git a/packages/login-with-qq/locales/zh_CN.yaml b/packages/login-with-qq/locales/zh_CN.yaml new file mode 100644 index 000000000..02169e562 --- /dev/null +++ b/packages/login-with-qq/locales/zh_CN.yaml @@ -0,0 +1 @@ +Login with QQ: 使用 QQ 登录 \ No newline at end of file diff --git a/packages/login-with-qq/package.json b/packages/login-with-qq/package.json new file mode 100644 index 000000000..58ab94a0c --- /dev/null +++ b/packages/login-with-qq/package.json @@ -0,0 +1,19 @@ +{ + "name": "@hydrooj/login-with-qq", + "version": "0.0.1", + "main": "package.json", + "repository": "git@github.com:hydro-dev/Hydro.git", + "author": "undefined ", + "license": "MIT", + "scripts": { + "lint": "eslint lib.ts service.ts --fix", + "build": "tsc" + }, + "dependencies": { + "hydrooj": "^2.12.1", + "ws": "^7.3.1" + }, + "devDependencies": { + "@types/ws": "^7.2.6" + } +} \ No newline at end of file diff --git a/packages/login-with-qq/service.ts b/packages/login-with-qq/service.ts new file mode 100644 index 000000000..5d8af9dc0 --- /dev/null +++ b/packages/login-with-qq/service.ts @@ -0,0 +1,35 @@ +import { } from 'hydrooj'; +import WebSocket from 'ws'; + +export async function postInit() { + const { system, token } = global.Hydro.model; + const [url, accessToken] = await system.getMany(['login-with-qq.url', 'login-with-qq.token']); + if (!url) return; + const headers: Record = {}; + if (accessToken) headers.Authorization = `Bearer ${accessToken}`; + const socket = new WebSocket(url, { headers }); + socket.on('error', console.error); + socket.on('message', async (message) => { + const payload = JSON.parse(message.toString()); + if (payload.post_type !== 'message') return; + if (payload.message.startsWith('login ')) { + const secret = payload.message.split(' ')[1]; + await token.coll.updateOne( + { secret, tokenType: token.TYPE_OAUTH }, + { + $set: { + email: `${payload.sender.user_id}@qq.com`, + username: payload.sender.nickname, + }, + }, + ); + } + }); + await new Promise((resolve) => { + socket.once('open', () => { + resolve(); + }); + }); +} + +global.Hydro.postInit.push(postInit); diff --git a/packages/login-with-qq/setting.yaml b/packages/login-with-qq/setting.yaml new file mode 100644 index 000000000..2ffa48318 --- /dev/null +++ b/packages/login-with-qq/setting.yaml @@ -0,0 +1,15 @@ +url: + type: text + category: system + desc: cqhttp ws api url + name: url +token: + type: text + category: system + desc: cqhttp token + name: token +id: + type: text + category: system + desc: QQ account id + name: id \ No newline at end of file diff --git a/packages/login-with-qq/tsconfig.json b/packages/login-with-qq/tsconfig.json new file mode 100644 index 000000000..aa7d73857 --- /dev/null +++ b/packages/login-with-qq/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es2019", + "module": "commonjs", + "esModuleInterop": true, + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "composite": true, + "strictBindCallApply": true, + "experimentalDecorators": true, + "outDir": ".", + "rootDir": "." + }, + "include": [ + "*.ts" + ], + "exclude": [] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 7cb762c78..279e1209f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,7 @@ { "path": "packages/login-with-github" }, { "path": "packages/login-with-google" }, { "path": "packages/login-with-osu" }, + { "path": "packages/login-with-qq" }, { "path": "packages/migrate-vijos" }, { "path": "tsconfig.build.json" }, ],