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.
73 lines
2.3 KiB
73 lines
2.3 KiB
import {
|
|
SlashCreator as Creator,
|
|
RespondFunction,
|
|
Server,
|
|
SlashCreatorOptions,
|
|
TransformedRequest
|
|
} from 'slash-create';
|
|
import { FetchRequestHandler } from './util/requestHandler';
|
|
import { verify } from './util/verify';
|
|
|
|
// @ts-expect-error doesn't like _onRequest
|
|
export class SlashCreator extends Creator {
|
|
/** The request handler for the creator */
|
|
readonly requestHandler: FetchRequestHandler;
|
|
|
|
/** @param opts The options for the creator */
|
|
constructor(opts: SlashCreatorOptions) {
|
|
// eslint-disable-next-line constructor-super
|
|
super(opts);
|
|
// @ts-ignore
|
|
this.requestHandler = new FetchRequestHandler(this);
|
|
}
|
|
|
|
/**
|
|
* Attaches a server to the creator.
|
|
* @param server The server to use
|
|
*/
|
|
withServer(server: Server) {
|
|
if (this.server) throw new Error('A server was already set in this creator.');
|
|
this.server = server;
|
|
|
|
if (this.server.isWebserver) {
|
|
if (!this.options.publicKey) throw new Error('A public key is required to be set when using a webserver.');
|
|
// @ts-ignore
|
|
this.server.createEndpoint(this.options.endpointPath as string, this._onRequest.bind(this));
|
|
// @ts-ignore
|
|
} else this.server.handleInteraction((interaction) => this._onInteraction(interaction, null, false));
|
|
|
|
return this;
|
|
}
|
|
|
|
// Overwriting the verification method to use Web Crypto API and use waitUntil for the promise
|
|
private async _onRequest(treq: TransformedRequest, respond: RespondFunction, wait: (f: any) => void) {
|
|
this.emit('debug', 'Got request');
|
|
|
|
// Verify request
|
|
const signature = treq.headers['x-signature-ed25519'] as string;
|
|
const timestamp = treq.headers['x-signature-timestamp'] as string;
|
|
|
|
// Check if both signature and timestamp exists, and the timestamp isn't past due.
|
|
if (
|
|
!signature ||
|
|
!timestamp ||
|
|
parseInt(timestamp) < (Date.now() - (this.options.maxSignatureTimestamp as number)) / 1000
|
|
)
|
|
return respond({
|
|
status: 401,
|
|
body: 'Invalid signature'
|
|
});
|
|
|
|
if (!(await verify(treq))) {
|
|
this.emit('debug', 'A request failed to be verified');
|
|
this.emit('unverifiedRequest', treq);
|
|
return respond({
|
|
status: 401,
|
|
body: 'Invalid signature'
|
|
});
|
|
}
|
|
|
|
// @ts-expect-error
|
|
wait(this._onInteraction(treq.body, respond, true).catch(() => {}));
|
|
}
|
|
}
|
|
|