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

View file

@ -1,24 +1,35 @@
#!/usr/bin/env -S deno run --allow-read --allow-write --allow-net --allow-env --unstable-kv
import { log_from, read_secrets, root_path, SimpleResult, wait } from "./utils.ts";
import { log_from, read_conf, root_path, SimpleResult, wait } from "./utils.ts";
import { State } from "./state.ts";
import { RuleSet } from "./rules.ts";
import { EpitlsBot } from "./bot.ts";
import { CriApi } from "./cri.ts";
import { Emailer } from "./email.ts";
import { WebVerifier } from "./verifier.ts";
const log = (...args: unknown[]) => log_from(import.meta.url, ...args);
async function main() {
const secrets = await read_secrets(root_path() + "/secrets.json");
const conf = await read_conf(root_path() + "/conf.json");
const rules = await RuleSet.from_file(root_path() + "/rules.json");
log("Loaded rules for", rules.size(), "roles.");
const state = await State.from_dir(root_path() + "/local");
log("Loaded state with", await state.users_count(), "users.");
const bot = new EpitlsBot(secrets.discord_bot_token);
const bot = new EpitlsBot(conf.discord.bot_token);
await bot.start();
log(`Started bot '${bot.bot_name()}' .`);
const cri_api = new CriApi(secrets.cri_token);
const service = new Service(state, bot, cri_api, rules);
const verifier = new WebVerifier(conf.verif_http);
await verifier.start();
log(`Started web verifier at '${verifier.url()}' .`);
const cri_api = new CriApi(conf.cri.cri_token);
const mailer = new Emailer(conf.email_smtp);
const service = new Service(state, bot, cri_api, rules, mailer, verifier);
await service.serve();
}
@ -30,25 +41,38 @@ class Service {
bot;
cri_api;
rules;
emailer;
verifier;
constructor(state: State, bot: EpitlsBot, cri_api: CriApi, rules: RuleSet) {
constructor(state: State, bot: EpitlsBot, cri_api: CriApi, rules: RuleSet, emailer: Emailer, verifier: WebVerifier) {
this.state = state;
this.bot = bot;
this.cri_api = cri_api;
this.rules = rules;
this.emailer = emailer;
this.verifier = verifier;
}
/**
* Main loops.
* Launches main loops.
*/
async serve() {
await this.update_all_users_roles();
// for all received associations, trigger the association procedure.
(async () => {
for await (const { discord_user_id, cri_login, callback } of this.bot.receive_associations()) {
this.association_procedure(discord_user_id, cri_login).then(callback);
}
})();
// for all links that must be sent, trigger mail sending.
(async () => {
for await (const { cri_login, discord_id, link } of this.verifier.links_to_send()) {
const username = await this.bot.get_username(discord_id);
this.emailer.send_confirmation_mail(username ?? "<unknown>", cri_login + "@epita.fr", link);
}
})();
}
async update_all_users_roles() {
@ -61,15 +85,18 @@ class Service {
async update_user_roles(cri_login: string, discord_user_id: string) {
const groups = await this.cri_api.groups_of(cri_login);
// log("found groups", groups);
const roles = groups.map((group) => this.rules.roles_for_group(group)).flat();
// log("found setting roles", roles);
for (const { guild_id, role_id } of roles) await this.bot.assign_role(discord_user_id, guild_id, role_id);
}
async association_procedure(discord_user_id: string, cri_login: string): Promise<SimpleResult> {
try {
await wait(1000);
if (!await this.cri_api.user_exists(cri_login)) return "No such login.";
this.state.set_user(discord_user_id, cri_login);
const res = await this.verifier.verification(discord_user_id, cri_login);
if (res !== true) return res;
await this.state.set_user(discord_user_id, cri_login);
await this.update_user_roles(cri_login, discord_user_id);
} catch (error) {
console.error(error);