fix interactions, apparently cfw doesn't speak Buffer

This commit is contained in:
41666 2022-02-03 22:57:37 -05:00
parent 7007cfea9d
commit 544ef1b2f0
5 changed files with 56 additions and 20 deletions

View file

@ -10,10 +10,15 @@ export const helloWorld: InteractionHandler = (
interaction: InteractionRequest, interaction: InteractionRequest,
context: Context context: Context
): InteractionResponse => { ): InteractionResponse => {
console.log({ interaction });
return { return {
type: InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE, type: InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE,
data: { data: {
content: `Hey there, ${interaction.member?.nick || interaction.user?.username}`, content: `Hey there, ${
interaction.member?.nick ||
interaction.member?.user?.username ||
interaction.user?.username
}`,
}, },
}; };
}; };

View file

@ -13,27 +13,50 @@ export const verifyRequest = async (
request: Request, request: Request,
interaction: InteractionRequest interaction: InteractionRequest
): Promise<boolean> => { ): Promise<boolean> => {
const timestamp = request.headers.get('x-signature-timestamp'); try {
const signature = request.headers.get('x-signature-ed25519'); const timestamp = request.headers.get('x-signature-timestamp');
const signature = request.headers.get('x-signature-ed25519');
if (!timestamp || !signature) { if (!timestamp || !signature) {
return false;
}
const key = await crypto.subtle.importKey(
'raw',
bufferizeHex(config.publicKey),
{ name: 'NODE-ED25519', namedCurve: 'NODE-ED25519', public: true } as any,
false,
['verify']
);
const verified = await crypto.subtle.verify(
'NODE-ED25519',
key,
bufferizeHex(signature),
bufferizeString(timestamp + JSON.stringify(interaction))
);
return verified;
} catch (e) {
return false; return false;
} }
};
const key = await crypto.subtle.importKey( // Cloudflare Workers + SubtleCrypto has no idea what a Buffer.from() is.
'raw', // What the fuck?
Buffer.from(config.publicKey, 'hex'), const bufferizeHex = (input: string) => {
{ name: 'NODE-ED25519', namedCurve: 'NODE-ED25519', public: true } as any, const buffer = new Uint8Array(input.length / 2);
false,
['verify']
);
return crypto.subtle.verify( for (let i = 0; i < input.length; i += 2) {
'NODE-ED25519', buffer[i / 2] = parseInt(input.substring(i, i + 2), 16);
key, }
Buffer.from(signature, 'hex'),
Buffer.from(timestamp + JSON.stringify(interaction)) return buffer;
); };
const bufferizeString = (input: string) => {
const encoder = new TextEncoder();
return encoder.encode(input);
}; };
export type InteractionHandler = (( export type InteractionHandler = ((
@ -59,7 +82,7 @@ export const runAsync = async (
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ body: JSON.stringify({
type: InteractionCallbackType.DEFERRED_UPDATE_MESSAGE, type: InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
data: { data: {
flags: handler.ephemeral ? InteractionFlags.EPHEMERAL : 0, flags: handler.ephemeral ? InteractionFlags.EPHEMERAL : 0,
...response.data, ...response.data,
@ -82,7 +105,7 @@ export const runAsync = async (
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ body: JSON.stringify({
type: InteractionCallbackType.DEFERRED_UPDATE_MESSAGE, type: InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
data: { data: {
content: "I'm sorry, I'm having trouble processing this request.", content: "I'm sorry, I'm having trouble processing this request.",
flags: InteractionFlags.EPHEMERAL, flags: InteractionFlags.EPHEMERAL,

View file

@ -30,14 +30,17 @@ export const handleInteraction: RoleypolyHandler = async (
} }
if (!(await verifyRequest(context.config, request, interaction))) { if (!(await verifyRequest(context.config, request, interaction))) {
console.warn('interactions: invalid signature');
return new Response('invalid request signature', { status: 401 }); return new Response('invalid request signature', { status: 401 });
} }
if (interaction.type !== InteractionType.APPLICATION_COMMAND) { if (interaction.type !== InteractionType.APPLICATION_COMMAND) {
if (interaction.type === InteractionType.PING) { if (interaction.type === InteractionType.PING) {
console.info('interactions: ping');
return json({ type: InteractionCallbackType.PONG }); return json({ type: InteractionCallbackType.PONG });
} }
console.warn('interactions: not application command');
return json({ err: 'not implemented' }, { status: 400 }); return json({ err: 'not implemented' }, { status: 400 });
} }

View file

@ -17,7 +17,7 @@ export const corsHeaders = {
'Access-Control-Max-Age': '86400', 'Access-Control-Max-Age': '86400',
}; };
export const noContent = () => new Response(null, { status: 204 }); export const noContent = () => new Response(null, { status: 204, headers: corsHeaders });
export const seeOther = (url: string) => export const seeOther = (url: string) =>
new Response( new Response(
`<!doctype html>If you are not redirected soon, <a href="${url}">click here.</a>`, `<!doctype html>If you are not redirected soon, <a href="${url}">click here.</a>`,

View file

@ -0,0 +1,5 @@
resource "discord-interactions_guild_command" "hello-world" {
name = "hello-world"
description = "Says hello!"
guild_id = "386659935687147521"
}