// std lib const crypto = require("crypto"); // npm imports const { Bot, Keyboard } = require("grammy"); // module imports const cache = require("./cache"); const request = require("./request"); // TODO: get value from confini // TODO: webhook support const bot = new Bot(""); // TODO: handle errors bot.command("start", async (ctx) => { const tgLinked = await cache.get(ctx.msg.from.id); if (tgLinked) { await cache.set(tgLinked, crypto.randomBytes(16).toString("hex")); const res = await request.proxy(tgLinked); return ctx.reply(res.text); } const keyboard = new Keyboard(); return await ctx.reply( "Click on the button below to link your phone number.", { reply_markup: keyboard.requestContact("Link Phone"), } ); }); // TODO: handle errors bot.on("message:text", async (ctx) => { const tgLinked = await cache.get(ctx.msg.from.id); if (tgLinked) { const res = await request.proxy(tgLinked, ctx.msg.text); if (res.code !== "END") { return ctx.reply(res.text); } return await cache.del(tgLinked); } return await ctx.reply( "Session expired or account not linked. /start the bot again to access your Sarafu account." ); }); // TODO: handle errors bot.on("msg:contact", async (ctx) => { // TODO: check if msg is reply from bot to prevent contact share bypass const contact = ctx.msg.contact; if (contact.phone_number.slice(0, 4) !== "+254") { return ctx.reply("Sarafu is only available in Kenya at the moment."); } // TODO: use contact.user_id in actual guard to prevent contact share bypass await cache.set(ctx.msg.from.id, contact.phone_number.slice(1)); return ctx.reply( "Phone number successfully linked. /start the bot again to access your Sarafu account." ); }); bot.start();