import { createHash, createHmac } from 'crypto'; import { Context, ForbiddenError, Handler, Schema, Service, } from 'hydrooj'; // from https://www.svgrepo.com/svg/333610/telegram // eslint-disable-next-line max-len const icon = ''; export default class TelegramService extends Service { static inject = ['oauth']; static Config = Schema.object({ token: Schema.string().role('secret').required(), botLogin: Schema.string().required(), endpoint: Schema.string().default('https://api.telegram.org/bot'), canRegister: Schema.boolean().default(false), }); constructor(ctx: Context, config: ReturnType) { super(ctx, 'oauth.telegram'); ctx.oauth.provide('telegram', { text: 'Login with Telegram', name: 'Telegram', icon, canRegister: config.canRegister, callback: async function callback({ payload }) { let parsed; try { parsed = JSON.parse(payload); } catch (e) { throw new ForbiddenError('Invalid payload'); } const hash = parsed.hash; delete parsed.hash; const dataCheckString = Object.keys(parsed).sort().map((key) => (`${key}=${parsed[key]}`)).join('\n'); const secretKey = createHash('sha256').update(config.token).digest(); const dataCheckSum = createHmac('sha256', secretKey).update(dataCheckString).digest('hex'); if (hash !== dataCheckSum) throw new ForbiddenError('Invalid hash'); const { id, first_name, last_name, username, photo_url, } = parsed; const ret = { _id: id.toString(), email: `${id}@telegram.local`, bio: '', uname: [`${first_name} ${last_name}`, username, `telegram${id.toString()}`].filter((i) => i), avatar: `url:${photo_url}`, }; if (!ret.email) throw new ForbiddenError("You don't have a verified email."); return ret; }, async get(this: Handler) { this.response.body = { botLogin: config.botLogin }; this.response.template = 'telegram_login.html'; }, }); ctx.i18n.load('zh', { 'Login With Telegram': '使用 Telegram 登录', }); } }