implements web verification
This commit is contained in:
parent
a7799eb3b1
commit
440e8bf324
9 changed files with 303 additions and 28 deletions
115
src/verifier.ts
Normal file
115
src/verifier.ts
Normal 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" } });
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue