From e15bdc192a8e5710821a22acc823d405172b5c5f Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sun, 3 Dec 2023 00:11:22 +0800 Subject: [PATCH] add reg, hw will use imei instead of token --- src/func/hook.ts | 76 ++++++++++++++++++++++++++++++++++++------------ src/func/push.ts | 14 +++++---- src/func/reg.ts | 18 ++++++++++++ src/index.ts | 2 ++ 4 files changed, 86 insertions(+), 24 deletions(-) create mode 100644 src/func/reg.ts diff --git a/src/func/hook.ts b/src/func/hook.ts index 074c2d1..172810f 100644 --- a/src/func/hook.ts +++ b/src/func/hook.ts @@ -4,6 +4,60 @@ import { IsValidUUID } from '../lib/uuid'; import { Status } from '../lib/status'; import { Wrap } from '../lib/wrapper'; +async function CMDBind(env: Env, chat_id: number, text: string): Promise { + const uuid = text.split('CMD:BIND:')[1]; + + // validate uuid + if (!IsValidUUID(uuid)) { + await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Invalid UUID (1)'); + return Wrap(Status.BadRequest, 'Invalid UUID (1)'); + } + + // NOTE: since KV is eventually consistent, these checks might not be correct + + // check if chat_id is already bounded to uuid + if ((await env.KV.get(`C:${chat_id}`)) !== null) { + await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Already Bounded'); + return Wrap(Status.OK, 'Already bounded'); + } + + // check if uuid is already bounded to chat_id + if ((await env.KV.get(`U:${uuid}`)) !== null) { + await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Invalid UUID (2)'); + return Wrap(Status.OK, 'Invalid UUID (2)'); + } + + // bind + await env.KV.put(`U:${uuid}`, chat_id.toString()); + await env.KV.put(`C:${chat_id}`, uuid); + + await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Bind Success'); + return Wrap(Status.OK, 'Bind Success'); +} + +async function CMDUnbind(env: Env, chat_id: number, text: string): Promise { + // check if chat_id is bounded + const uuid = await env.KV.get(`C:${chat_id}`); + if (uuid === null) { + await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Not Bounded'); + return Wrap(Status.OK, 'Not bounded'); + } + + // unbind + await env.KV.delete(`U:${uuid}`); + await env.KV.delete(`C:${chat_id}`); + + await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Unbind Success'); + return Wrap(Status.OK, 'Unbind Success'); +} + +type CMDHandler = (env: Env, chat_id: number, text: string) => Promise; +const cmd: { [prefix: string]: CMDHandler } = { + 'CMD:BIND:': CMDBind, + 'CMD:UNBIND': CMDUnbind, + // TODO: CMD:SEND: +}; + export async function FuncHook(request: Request, env: Env, ctx: ExecutionContext): Promise { if (request.method !== 'POST') return Wrap(Status.BadRequest, 'Only POST method is allowed'); @@ -18,25 +72,11 @@ export async function FuncHook(request: Request, env: Env, ctx: ExecutionContext console.debug(`[Hook] ${chat_id} ${text}`); - if (text.startsWith('BIND:')) { - const uuid = text.split(':')[1]; - if (!IsValidUUID(uuid)) return Wrap(Status.BadRequest, 'Invalid UUID'); - await env.KV.put(uuid, chat_id.toString()); - await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Bind Success'); - return Wrap(Status.OK, 'Bind successfully'); + for (const prefix in cmd) { + if (text.startsWith(prefix)) { + return cmd[prefix](env, chat_id, text); + } } - if (text.startsWith('UNBIND:')) { - const uuid = text.split(':')[1]; - if (!IsValidUUID(uuid)) return Wrap(Status.BadRequest, 'Invalid UUID'); - await env.KV.delete(uuid); - await new Bot(env.TG_BOT_TOKEN).send(chat_id, '[BOT] Unbind Success'); - return Wrap(Status.OK, 'Unbind successfully'); - } - - // TODO: Handle "SEND:" command - - // TODO: Handle Cited Message (Text or Voice) with command - return Wrap(Status.OK, 'Nothing Executed'); } diff --git a/src/func/push.ts b/src/func/push.ts index de68233..a552cc0 100644 --- a/src/func/push.ts +++ b/src/func/push.ts @@ -1,18 +1,20 @@ import { Bot } from '../lib/bot'; import { Env } from '../index'; -import { IsValidUUID } from '../lib/uuid'; import { Status } from '../lib/status'; import { Wrap } from '../lib/wrapper'; export async function FuncPush(request: Request, env: Env, ctx: ExecutionContext): Promise { if (request.method !== 'POST') return Wrap(Status.BadRequest, 'Only POST method is allowed'); - const token = request.headers.get('X-Auth-Token'); - if (!token) return Wrap(Status.BadRequest, 'Missing X-Auth-Token header'); - if (!IsValidUUID(token)) return Wrap(Status.BadRequest, 'Invalid Token'); + const imei = request.headers.get('X-Auth-Token'); + if (!imei) return Wrap(Status.BadRequest, 'Missing X-Auth-Token header'); + if (imei.length < 15 || imei.length > 17) return Wrap(Status.BadRequest, 'Invalid Token (1)'); - const chat_id = await env.KV.get(token); - if (!chat_id) return Wrap(Status.BadRequest, 'Invalid Token'); + const uuid = await env.KV.get(`I:${imei}`); + if (!uuid) return Wrap(Status.BadRequest, 'Invalid Token (2)'); + + const chat_id = await env.KV.get(`U:${uuid}`); + if (!chat_id) return Wrap(Status.BadRequest, 'Invalid Token (3)'); const bot = new Bot(env.TG_BOT_TOKEN); const message = await request.text(); diff --git a/src/func/reg.ts b/src/func/reg.ts new file mode 100644 index 0000000..4609a19 --- /dev/null +++ b/src/func/reg.ts @@ -0,0 +1,18 @@ +import { Env } from '../index'; +import { GenUUID } from '../lib/uuid'; +import { Status } from '../lib/status'; +import { Wrap } from '../lib/wrapper'; + +export async function FuncReg(request: Request, env: Env, ctx: ExecutionContext): Promise { + if (request.method !== 'POST') return Wrap(Status.BadRequest, 'Only POST method is allowed'); + + const imei = await request.text(); + if (!imei || imei.length < 15 || imei.length > 17) return Wrap(Status.BadRequest, 'Invalid IMEI'); + + const token = await env.KV.get(`I:${imei}`); + if (token) return Wrap(Status.OK, token); + + const new_token = GenUUID(); + await env.KV.put(`I:${imei}`, new_token); + return Wrap(Status.OK, new_token); +} diff --git a/src/index.ts b/src/index.ts index 9bf8007..dc4e0b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import { NotFound } from './lib/wrapper'; import { FuncPush } from './func/push'; import { FuncHook } from './func/hook'; +import { FuncReg } from './func/reg'; export interface Env { KV: KVNamespace; @@ -14,6 +15,7 @@ export type Handler = (request: Request, env: Env, ctx: ExecutionContext) => Pro const routes: { [page: string]: Handler } = { '/push': FuncPush, '/hook': FuncHook, + '/reg': FuncReg, }; export default {