1
Fork 0
mirror of https://github.com/Steffo99/festa.git synced 2024-12-22 14:44:21 +00:00
festa/pages/api/auth/telegram.ts

123 lines
4.7 KiB
TypeScript

import { database } from "../../../utils/prismaClient";
import { NextApiRequest, NextApiResponse } from "next";
import { TelegramLoginObject } from "../../../components/auth/telegram/processing";
import { default as cryptoRandomString } from "crypto-random-string"
import { festaAPI } from "../../../utils/api";
import { festaNoAuth } from "../../../utils/api/authenticator";
import { festaJsonSchemaBody } from "../../../utils/api/bodyValidator";
import { TelegramLoginResponse } from "react-telegram-login";
import { Response } from "../../../utils/api/throwables";
import { festaNoQuery } from "../../../utils/api/queryValidator";
type Config = {
botToken: string,
hashExpirationMs: number,
tokenExpirationMs: number,
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await festaAPI(req, res, {
configurator: {
perform: async () => {
const botToken = process.env.TELEGRAM_TOKEN
if (!botToken) {
throw Response.error({ status: 503, message: "`TELEGRAM_TOKEN` was not set up" })
}
const hashExpirationMs = parseInt(process.env.TELEGRAM_HASH_EXPIRATION_MS!) // TypeScript type is wrong?
if (!hashExpirationMs) {
throw Response.error({ status: 503, message: "`TELEGRAM_HASH_EXPIRATION_MS` was not set up" })
}
const tokenExpirationMs = parseInt(process.env.FESTA_TOKEN_EXPIRATION_MS!) // TypeScript type is wrong?
if (!tokenExpirationMs) {
throw Response.error({ status: 503, message: "`FESTA_TOKEN_EXPIRATION_MS` was not set up" })
}
return { botToken, hashExpirationMs, tokenExpirationMs }
}
},
authenticator: festaNoAuth,
queryValidator: festaNoQuery,
bodyValidator: festaJsonSchemaBody<TelegramLoginResponse>({
type: "object",
properties: {
id: { type: "integer" },
first_name: { type: "string" },
auth_date: { type: "integer" },
hash: { type: "string" },
last_name: { type: "string", nullable: true },
username: { type: "string", nullable: true },
photo_url: { type: "string", nullable: true },
lang: { type: "string", nullable: true },
},
required: [
"id",
"first_name",
"auth_date",
"hash",
]
}),
executor: {
methods: ["POST"],
perform: async ({ config, body }) => {
try {
var tlo: TelegramLoginObject = new TelegramLoginObject(body!)
}
catch (e) {
throw Response.error({ status: 422, message: "Telegram Login response validation failed" })
}
if (!tlo.isRecent(config.hashExpirationMs)) {
throw Response.error({ status: 408, message: "Telegram login data is not recent" })
}
if (!tlo.isValid(config.botToken)) {
throw Response.error({ status: 401, message: "Telegram login data has been tampered" })
}
const accountTelegram = await database.accountTelegram.upsert({
where: {
telegramId: tlo.id
},
create: {
...tlo.toDatabase(),
user: {
create: {
displayName: tlo.toTelegramName(),
displayAvatarURL: tlo.photoUrl,
}
}
},
update: {
...tlo.toDatabase(),
user: {
update: {
displayName: tlo.toTelegramName(),
displayAvatarURL: tlo.photoUrl,
}
}
}
})
const token = await database.token.create({
data: {
userId: accountTelegram.userId,
token: cryptoRandomString({ length: 16, type: "base64" }),
expiresAt: new Date(tlo.authDate.getTime() + config.tokenExpirationMs)
},
include: {
user: true,
}
})
return token
}
},
})
}