From a49d13c8a9a6507ad80d4b7f4867fb02dfed3be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Moreau?= Date: Tue, 31 May 2022 12:08:26 +0200 Subject: [PATCH] feature: suivi de certifications --- app.yml | 8 +++- src/lib/dwatch.ts | 2 + src/lib/types/conf.ts | 7 +++ .../watchers/bma/certifications-watcher.ts | 48 +++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/lib/watchers/bma/certifications-watcher.ts diff --git a/app.yml b/app.yml index 629cf38..41538be 100644 --- a/app.yml +++ b/app.yml @@ -2,8 +2,8 @@ connectionTimeout: 10000 # 10" waitingDelay: 5000 # 5" recallDelay: 60000 websocketServers: - - name: cgeek V2S - address: wss://gdev.cgeek.fr +# - name: cgeek V2S +# address: wss://gdev.cgeek.fr ws2pServers: # - address: ws://g1-test.cgeek.fr:22001 @@ -52,6 +52,10 @@ memberships: # - {address: https://g1-test.cgeek.fr, currency: ğtest, frequency: 86400, mustRemain: 7776000, pubkey: 78Tus1ajGnztK6FW7suYsprWFZUkiiG1bakuMNsHooWo, memberAlias: cgeek-dev} # Compte révoqué # - {address: https://g1-test.cgeek.fr, currency: ğtest, frequency: 86400, mustRemain: 7776000, pubkey: 4Ec3yqwfCxJM2pB3jCGrbUSvxqDGxasQcBCxCyA81Nwh, memberAlias: cgeek-test-revocation} # Compte révoqué +certifications: + # Tous les 1j et 1 an de prévenance + - {address: https://g1.cgeek.fr, frequency: 86400, mustLongAtLeast: 31536000, mustRemainAtLeast: 10, pubkey: 2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ, name: cgeek ğ1 } + mail: enabled: false frequency: 3000 # 10" diff --git a/src/lib/dwatch.ts b/src/lib/dwatch.ts index 8184647..952e0a0 100644 --- a/src/lib/dwatch.ts +++ b/src/lib/dwatch.ts @@ -11,6 +11,7 @@ import {jsonWatcher} from "./watchers/wotwizard/json-watcher"; import {initConfMail} from './mail' import {membershipWatcher} from './watchers/bma/membership-watcher' import {websocketWatcher} from "./watchers/websocket/websocket-watcher"; +import {certificationsWatcher} from "./watchers/bma/certifications-watcher"; export async function dwatch(confFile: string) { @@ -26,5 +27,6 @@ export async function dwatch(confFile: string) { (await Promise.all((conf.headServers || []).map(headWatcher(conf)))).forEach(w => watchers.push(w)); (await Promise.all((conf.wwMeta || []).map(jsonWatcher(conf)))).forEach(w => watchers.push(w)); (await Promise.all((conf.memberships || []).map(membershipWatcher(conf)))).forEach(w => watchers.push(w)); + (await Promise.all((conf.certifications || []).map(certificationsWatcher(conf)))).forEach(w => watchers.push(w)); return watchers } diff --git a/src/lib/types/conf.ts b/src/lib/types/conf.ts index a8d17de..e85fd27 100644 --- a/src/lib/types/conf.ts +++ b/src/lib/types/conf.ts @@ -10,6 +10,7 @@ export interface Conf { headServers: ConfHead[] wwMeta: ConfWWMeta[] memberships: ConfMembership[] + certifications: ConfCertifications[] mail: ConfMail } @@ -52,6 +53,12 @@ export interface ConfMembership extends ConfURL { mustRemain: number } +export interface ConfCertifications extends ConfURL { + pubkey: string + mustRemainAtLeast: number + mustLongAtLeast: number +} + export interface ConfHead extends ConfURL { observedPubkey: string maxLateBlocks: number diff --git a/src/lib/watchers/bma/certifications-watcher.ts b/src/lib/watchers/bma/certifications-watcher.ts new file mode 100644 index 0000000..a1a1fd6 --- /dev/null +++ b/src/lib/watchers/bma/certifications-watcher.ts @@ -0,0 +1,48 @@ +import {Conf, ConfCertifications, ConfMembership} from "../../types/conf"; +import {urlWatcher, UrlWatcherResult} from '../abstract/url-watcher' +import {moment} from "duniter/app/lib/common-libs/moment"; + +export function certificationsWatcher(conf: Conf) { + + const URL_PATH = '/wot/certifiers-of/' + + return async (confCerts: ConfCertifications) => { + + function getSubjectTitle(state: string) { + return `State ${state} certifications of ${confCerts.name}` + } + + let state = 'INIT' + + return urlWatcher(conf, async (data) => { + const json = data as { + certifications: { uid: string, cert_time: { medianTime: number } }[] + } + const now = Math.floor(Date.now() / 1000) + const expiresSoon = json.certifications.filter((c:any) => { + const diff = now - c.cert_time.medianTime + return diff < confCerts.mustLongAtLeast + }) + const remainingDays = Math.floor(confCerts.mustLongAtLeast / (3600 * 24)) + const willExpireMessage = `${expiresSoon.length} certifications are going to expire in less than ${remainingDays.toFixed(0)} days` + if (json.certifications.length < confCerts.mustRemainAtLeast) { + state = 'ERROR' + return UrlWatcherResult.ko(`Not enough certifications`) + } else { + if (json.certifications.length - expiresSoon.length < confCerts.mustRemainAtLeast) { + state = 'WARNING' + return UrlWatcherResult.ko(willExpireMessage) + } + } + state = 'OK' + return UrlWatcherResult.ok(`${json.certifications.length} valid [${willExpireMessage}]`) + })({ + name: `certifications of ${confCerts.pubkey.substr(0, 6)} (${confCerts.name})`, + address: confCerts.address + URL_PATH + confCerts.pubkey, + frequency: confCerts.frequency + }, + () => getSubjectTitle('OK'), + () => getSubjectTitle(state), + () => getSubjectTitle('RECOVERED')) + } +}