You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
88 lines
3.2 KiB
88 lines
3.2 KiB
import {SavedWebhook} from "./SavedWebhook.js";
|
|
import {FastifyReply, FastifyRequest} from "fastify";
|
|
import {AccessToken, AuthorizationCode, ModuleOptions} from "simple-oauth2";
|
|
import pug from "pug";
|
|
import {renderError} from "./PugRenderer.js";
|
|
import {APIWebhook} from "discord-api-types";
|
|
import {getBaseUrl, getFirstValue, RouteWithQuerystring} from "./FastifyHelpers.js";
|
|
import { join } from "path";
|
|
|
|
interface DiscordWebhookToken extends AccessToken {
|
|
token: {webhook?: APIWebhook}
|
|
}
|
|
|
|
const AuthConfig: ModuleOptions["auth"] = {
|
|
tokenHost: "https://discord.com",
|
|
authorizePath: "/api/oauth2/authorize",
|
|
tokenPath: "/api/oauth2/token",
|
|
revokePath: "/api/oauth2/token/revoke",
|
|
}
|
|
|
|
export class DiscordWebhookHandler {
|
|
readonly webhook: SavedWebhook
|
|
readonly templateFilename: string
|
|
readonly config: ModuleOptions
|
|
readonly destinationFunc: () => string
|
|
constructor({webhook, templateFilename, appId, secret, destinationFunc}: {webhook: SavedWebhook, templateFilename: string, appId: string, secret: string, destinationFunc: () => string}) {
|
|
this.templateFilename = templateFilename
|
|
this.webhook = webhook
|
|
this.config = {
|
|
client: {
|
|
id: appId,
|
|
secret,
|
|
},
|
|
auth: AuthConfig,
|
|
}
|
|
this.destinationFunc = destinationFunc
|
|
}
|
|
async handleRequest(req: FastifyRequest<RouteWithQuerystring>, res: FastifyReply): Promise<void> {
|
|
const baseUrl = getBaseUrl(req)
|
|
const code = getFirstValue(req.query["code"]) ?? null
|
|
const client = new AuthorizationCode(this.config)
|
|
if (code === null) {
|
|
const authUrl = client.authorizeURL({
|
|
scope: ["applications.commands", "webhook.incoming"],
|
|
redirect_uri: req.url,
|
|
})
|
|
res.code(200)
|
|
res.type("text/html")
|
|
res.send(pug.renderFile(join("static/pages", this.templateFilename), {authUrl, baseUrl, isReset: this.webhook.isPresent}))
|
|
return
|
|
}
|
|
let token: DiscordWebhookToken
|
|
try {
|
|
token = await client.getToken({
|
|
code,
|
|
scope: ["applications.commands", "webhook.incoming"],
|
|
redirect_uri: getBaseUrl(req) + "setup/gameChannel"
|
|
}) as DiscordWebhookToken
|
|
} catch (e) {
|
|
return renderError({
|
|
baseUrl,
|
|
res: res,
|
|
error: e,
|
|
context: "exchanging the code you gave me for a token"
|
|
})
|
|
}
|
|
if (!token.token.webhook) {
|
|
return renderError({
|
|
baseUrl,
|
|
res: res,
|
|
error: "token did not contain webhook",
|
|
context: "processing the token I received"
|
|
})
|
|
}
|
|
const wasSet = this.webhook.isPresent
|
|
try {
|
|
await this.webhook.replaceHook(token.token.webhook)
|
|
} catch (e) {
|
|
return renderError({
|
|
baseUrl,
|
|
res: res,
|
|
error: e,
|
|
context: `saving the new webhook${wasSet ? " and deleting the old one" : ""}`
|
|
})
|
|
}
|
|
res.redirect(this.destinationFunc())
|
|
}
|
|
} |