mirror of
https://github.com/xHyroM/roles-bot.git
synced 2024-11-09 19:08:05 +01:00
feat: add things
This commit is contained in:
parent
eebc948a58
commit
05aa790303
12 changed files with 156 additions and 43 deletions
|
@ -13,11 +13,13 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cloudflare/workers-types": "^3.17.0",
|
"@cloudflare/workers-types": "^3.17.0",
|
||||||
"@types/jest": "^29.1.2",
|
"@types/jest": "^29.1.2",
|
||||||
"discord-api-types": "^0.37.14",
|
|
||||||
"esbuild": "^0.15.11",
|
"esbuild": "^0.15.11",
|
||||||
"eslint": "^8.25.0",
|
"eslint": "^8.25.0",
|
||||||
"jest": "^29.2.0",
|
"jest": "^29.2.0",
|
||||||
"miniflare": "^2.10.0",
|
"miniflare": "^2.10.0",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "^4.8.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"discord-api-types": "^0.37.37"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
|
import { InteractionResponseType } from "discord-api-types/v10";
|
||||||
import { Command } from "../structs/Command";
|
import { Command } from "../structs/Command";
|
||||||
|
import respond from "../utils/respond";
|
||||||
|
|
||||||
new Command({
|
new Command({
|
||||||
name: "setup",
|
name: "setup",
|
||||||
|
run: async () => {
|
||||||
|
return respond({
|
||||||
|
type: InteractionResponseType.ChannelMessageWithSource,
|
||||||
|
data: {
|
||||||
|
content: "Setup",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,51 @@
|
||||||
import "./commands/setup";
|
import "./commands/setup";
|
||||||
import { COMMANDS } from "./registers";
|
import {
|
||||||
|
APIApplicationCommandInteraction,
|
||||||
|
APIMessageComponentInteraction,
|
||||||
|
APIPingInteraction,
|
||||||
|
InteractionResponseType,
|
||||||
|
InteractionType,
|
||||||
|
} from "discord-api-types/v10";
|
||||||
|
import { COMMANDS, COMPONENTS } from "./registers";
|
||||||
|
import { verify } from "./utils/verify";
|
||||||
|
import respond from "./utils/respond";
|
||||||
|
|
||||||
console.log(COMMANDS);
|
console.log(COMMANDS);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
fetch: (request: Request) => {
|
fetch: async (request: Request) => {
|
||||||
console.log(request);
|
if (
|
||||||
return new Response("asda");
|
!request.headers.get("X-Signature-Ed25519") ||
|
||||||
|
!request.headers.get("X-Signature-Timestamp")
|
||||||
|
)
|
||||||
|
return Response.redirect("https://xhyrom.dev");
|
||||||
|
if (!(await verify(request)))
|
||||||
|
return new Response("Invalid request signature", { status: 401 });
|
||||||
|
|
||||||
|
const interaction = (await request.json()) as
|
||||||
|
| APIPingInteraction
|
||||||
|
| APIApplicationCommandInteraction
|
||||||
|
| APIMessageComponentInteraction;
|
||||||
|
|
||||||
|
if (interaction.type === InteractionType.Ping)
|
||||||
|
return respond({
|
||||||
|
type: InteractionResponseType.Pong,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (interaction.type === InteractionType.ApplicationCommand) {
|
||||||
|
const command = COMMANDS.find(
|
||||||
|
(cmd) => cmd.name === interaction.data.name,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!command) return new Response("Unknown command", { status: 404 });
|
||||||
|
return command.run(interaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
const component = COMPONENTS.find(
|
||||||
|
(cmp) => cmp.id === interaction.data.custom_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!component) return new Response("Unknown component", { status: 404 });
|
||||||
|
return component.run(interaction);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Command } from "./structs/Command";
|
import { Command } from "./structs/Command";
|
||||||
import { Listener } from "./structs/Listener";
|
import { Component } from "./structs/Component";
|
||||||
|
|
||||||
export const COMMANDS: Command[] = [];
|
export const COMMANDS: Command[] = [];
|
||||||
export const LISTENERS: Listener[] = [];
|
export const COMPONENTS: Component[] = [];
|
||||||
|
|
||||||
export const registerCommand = (command: Command) => {
|
export const registerCommand = (command: Command) => {
|
||||||
COMMANDS.push(command);
|
COMMANDS.push(command);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const registerListener = (listener: Listener) => {
|
export const registerComponent = (component: Component) => {
|
||||||
LISTENERS.push(listener);
|
COMPONENTS.push(component);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
|
import { APIApplicationCommandInteraction } from "discord-api-types/v10";
|
||||||
import { registerCommand } from "../registers";
|
import { registerCommand } from "../registers";
|
||||||
|
|
||||||
interface CommandOptions {
|
interface CommandOptions {
|
||||||
name: string;
|
name: string;
|
||||||
|
run: (interaction: APIApplicationCommandInteraction) => Promise<Response>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Command {
|
export class Command {
|
||||||
public name: string;
|
public name: string;
|
||||||
|
public run: (
|
||||||
|
interaction: APIApplicationCommandInteraction,
|
||||||
|
) => Promise<Response>;
|
||||||
|
|
||||||
constructor(options: CommandOptions) {
|
constructor(options: CommandOptions) {
|
||||||
this.name = options.name;
|
this.name = options.name;
|
||||||
|
this.run = options.run;
|
||||||
|
|
||||||
registerCommand(this);
|
registerCommand(this);
|
||||||
}
|
}
|
||||||
|
|
21
packages/bot/src/structs/Component.ts
Normal file
21
packages/bot/src/structs/Component.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { APIMessageComponentInteraction } from "discord-api-types/v10";
|
||||||
|
import { registerComponent } from "../registers";
|
||||||
|
|
||||||
|
interface ComponentOptions {
|
||||||
|
id: string;
|
||||||
|
run: (interaction: APIMessageComponentInteraction) => Promise<Response>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Component {
|
||||||
|
public id: string;
|
||||||
|
public run: (
|
||||||
|
interaction: APIMessageComponentInteraction,
|
||||||
|
) => Promise<Response>;
|
||||||
|
|
||||||
|
constructor(options: ComponentOptions) {
|
||||||
|
this.id = options.id;
|
||||||
|
this.run = options.run;
|
||||||
|
|
||||||
|
registerComponent(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +0,0 @@
|
||||||
import { registerListener } from "../registers";
|
|
||||||
|
|
||||||
interface ListenerOptions {
|
|
||||||
name: string;
|
|
||||||
once: boolean | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Listener {
|
|
||||||
public name: string;
|
|
||||||
public once: boolean;
|
|
||||||
|
|
||||||
constructor(options: ListenerOptions) {
|
|
||||||
this.name = options.name;
|
|
||||||
this.once = options.once ?? false;
|
|
||||||
|
|
||||||
registerListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
3
packages/bot/src/types.d.ts
vendored
Normal file
3
packages/bot/src/types.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// secrets: wrangler secret put <name>
|
||||||
|
declare const publicKey: string;
|
||||||
|
declare const token: string;
|
7
packages/bot/src/utils/respond.ts
Normal file
7
packages/bot/src/utils/respond.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { APIInteractionResponse } from "discord-api-types/v10";
|
||||||
|
|
||||||
|
export default function (response: APIInteractionResponse) {
|
||||||
|
return new Response(JSON.stringify(response), {
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
});
|
||||||
|
}
|
38
packages/bot/src/utils/verify.ts
Normal file
38
packages/bot/src/utils/verify.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// from https://gist.github.com/devsnek/77275f6e3f810a9545440931ed314dc1
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function hex2bin(hex: string) {
|
||||||
|
const buf = new Uint8Array(Math.ceil(hex.length / 2));
|
||||||
|
for (let i = 0; i < buf.length; i++) {
|
||||||
|
buf[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PUBLIC_KEY = crypto.subtle.importKey(
|
||||||
|
"raw",
|
||||||
|
hex2bin(publicKey),
|
||||||
|
{
|
||||||
|
name: "NODE-ED25519",
|
||||||
|
namedCurve: "NODE-ED25519",
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
["verify"],
|
||||||
|
);
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
export async function verify(request: Request) {
|
||||||
|
// rome-ignore lint/style/noNonNullAssertion: its fine
|
||||||
|
const signature = hex2bin(request.headers.get("X-Signature-Ed25519")!);
|
||||||
|
const timestamp = request.headers.get("X-Signature-Timestamp");
|
||||||
|
const unknown = await request.clone().text();
|
||||||
|
|
||||||
|
return await crypto.subtle.verify(
|
||||||
|
"NODE-ED25519",
|
||||||
|
await PUBLIC_KEY,
|
||||||
|
signature,
|
||||||
|
encoder.encode(timestamp + unknown),
|
||||||
|
);
|
||||||
|
}
|
|
@ -9,6 +9,10 @@ importers:
|
||||||
version: 12.0.0
|
version: 12.0.0
|
||||||
|
|
||||||
packages/bot:
|
packages/bot:
|
||||||
|
dependencies:
|
||||||
|
discord-api-types:
|
||||||
|
specifier: ^0.37.37
|
||||||
|
version: 0.37.37
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@cloudflare/workers-types':
|
'@cloudflare/workers-types':
|
||||||
specifier: ^3.17.0
|
specifier: ^3.17.0
|
||||||
|
@ -16,9 +20,6 @@ importers:
|
||||||
'@types/jest':
|
'@types/jest':
|
||||||
specifier: ^29.1.2
|
specifier: ^29.1.2
|
||||||
version: 29.1.2
|
version: 29.1.2
|
||||||
discord-api-types:
|
|
||||||
specifier: ^0.37.14
|
|
||||||
version: 0.37.14
|
|
||||||
esbuild:
|
esbuild:
|
||||||
specifier: ^0.15.11
|
specifier: ^0.15.11
|
||||||
version: 0.15.11
|
version: 0.15.11
|
||||||
|
@ -2324,9 +2325,9 @@ packages:
|
||||||
path-type: 4.0.0
|
path-type: 4.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/discord-api-types@0.37.14:
|
/discord-api-types@0.37.37:
|
||||||
resolution: {integrity: sha512-byBH7SfDCMJwxdqeS8k5sihltH88/YPhuwx+vF2cftSxFLdxyHyU/ZxDL3bq+LB2c4ls/TymE76/ISlLfniUXg==}
|
resolution: {integrity: sha512-LDMBKzl/zbvHO/yCzno5hevuA6lFIXJwdKSJZQrB+1ToDpFfN9thK+xxgZNR4aVkI7GHRDja0p4Sl2oYVPnHYg==}
|
||||||
dev: true
|
dev: false
|
||||||
|
|
||||||
/dlv@1.1.3:
|
/dlv@1.1.3:
|
||||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
"organizeImports": {
|
"organizeImports": {
|
||||||
"enabled": false
|
"enabled": false
|
||||||
},
|
},
|
||||||
|
"files": {
|
||||||
|
"ignore": ["dist/**"]
|
||||||
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
|
|
Loading…
Reference in a new issue