implements web verification

This commit is contained in:
Matthieu Jolimaitre 2024-02-02 16:45:08 +01:00
parent a7799eb3b1
commit 440e8bf324
9 changed files with 303 additions and 28 deletions

115
src/verifier.ts Normal file
View file

@ -0,0 +1,115 @@
import { v1 as uuid } from "https://deno.land/std@0.213.0/uuid/mod.ts";
import { channel, log_from, Resolver, SimpleResult, split_promise, wait } from "./utils.ts";
const log = (...args: unknown[]) => log_from(import.meta.url, ...args);
export type WebVerifierConf = {
port: number;
url_prefix: string;
};
export type LinkToSend = {
discord_id: string;
cri_login: string;
link: string;
};
export class WebVerifier {
conf;
awaiting;
link_channel;
public constructor(conf: WebVerifierConf) {
this.conf = conf;
this.awaiting = new Map<string, Resolver<SimpleResult>>();
this.link_channel = channel<LinkToSend>();
}
public async start() {
const { promise, resolver } = split_promise<void>();
Deno.serve({
hostname: "0.0.0.0",
port: this.conf.port,
onListen: () => resolver(),
}, (request) => this.serve(request));
return await promise;
}
public async verification(discord_id: string, cri_login: string) {
const { link, uid } = this.create_verif_link();
const { promise, resolver } = split_promise<SimpleResult>();
this.awaiting.set(uid, resolver);
log(`Created verification link '${link}' for discord id '${discord_id}' to cri login '${cri_login}'.`);
this.link_channel.send({ cri_login, discord_id, link });
this.start_peremption(uid);
return await promise;
}
public async *links_to_send() {
while (true) yield await this.link_channel.receive();
}
public url() {
return `http://${this.conf.url_prefix}`;
}
private serve(request: Request): Response {
const url = new URL(request.url);
if (!url.pathname.startsWith("/verify/")) return response_failure("Invalid path.");
const [uid] = url.pathname.slice("/verify/".length).split("/");
const resolver = this.awaiting.get(uid);
if (resolver === undefined) return response_failure("Invalid verification link.");
resolver(true);
this.awaiting.delete(uid);
log(`Verified link ${uid} successfully.`);
return response_success();
}
private create_verif_link() {
const uid = uuid.generate() as string;
const link = `http://${this.conf.url_prefix}/verify/${uid}`;
return { uid, link };
}
private async start_peremption(uid: string) {
await wait(5 * 60 * 1000); // 5 mins
const resolver = this.awaiting.get(uid);
if (resolver === undefined) return;
resolver("Verification link timeout.");
this.awaiting.delete(uid);
log(`Link '${uid}' timed out.`);
}
}
function response_failure(message: string) {
const body = `<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Epitls Verification</title>
</head>
<body>
<pre>
Failure :
${message}
</pre>
</body>
</html>
`;
return new Response(body, { headers: { "Content-Type": "text/html" } });
}
function response_success() {
const body = `<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Epitls Verification</title>
</head>
<body>
<pre>
Verified successfully.
</pre>
</body>
</html>
`;
return new Response(body, { headers: { "Content-Type": "text/html" } });
}