diff --git a/app/client/models/AdminChecks.ts b/app/client/models/AdminChecks.ts index bd5a8cee..bbea371b 100644 --- a/app/client/models/AdminChecks.ts +++ b/app/client/models/AdminChecks.ts @@ -53,7 +53,7 @@ export class AdminChecks { const {id} = probe; let result = this._results.get(id); if (!result) { - result = Observable.create(this._parent, {}); + result = Observable.create(this._parent, {status: 'none'}); this._results.set(id, result); } let request = this._requests.get(id); @@ -108,7 +108,7 @@ export class AdminCheckRunner { public start() { let result = this.results.get(this.id); if (!result) { - result = Observable.create(this.parent, {}); + result = Observable.create(this.parent, {status: 'none'}); this.results.set(this.id, result); } } diff --git a/app/client/ui/AdminPanel.ts b/app/client/ui/AdminPanel.ts index 48703444..dfecb1ff 100644 --- a/app/client/ui/AdminPanel.ts +++ b/app/client/ui/AdminPanel.ts @@ -179,7 +179,7 @@ Please log in as an administrator.`)), use => { const req = this._checks.requestCheckById(use, 'sandboxing'); const result = req ? use(req.result) : undefined; - const success = result?.success; + const success = result?.status === 'success'; const details = result?.details as SandboxingBootProbeDetails|undefined; if (!details) { return cssValueLabel(t('unknown')); @@ -217,7 +217,8 @@ Please log in as an administrator.`)), return cssValueLabel(cssErrorText('unavailable')); } - const { success, details } = result; + const { status, details } = result; + const success = status === 'success'; const loginSystemId = details?.loginSystemId; if (!success || !loginSystemId) { @@ -500,10 +501,10 @@ Please log in as an administrator.`)), { style: 'margin-top: 0px; padding-top: 0px;' }, ), result.verdict ? dom('pre', result.verdict) : null, - (result.success === undefined) ? null : + (result.status === 'none') ? null : dom('p', - result.success ? t('Check succeeded.') : t('Check failed.')), - (result.done !== true) ? null : + (result.status === 'success') ? t('Check succeeded.') : t('Check failed.')), + (result.status !== 'none') ? null : dom('p', t('No fault detected.')), (details?.info === undefined) ? null : [ cssCheckHeader(t('Notes')), @@ -530,12 +531,21 @@ Please log in as an administrator.`)), * visualization of the results can be elaborated in future. */ private _encodeSuccess(result: BootProbeResult) { - if (result.success === undefined) { return '―'; } - if (result.success) { return '✅'; } - if (result.severity === 'warning') { return '❗'; } - if (result.severity === 'hmm') { return '?'; } - // remaining case is a fault. - return '❌'; + switch (result.status) { + case 'success': + return '✅'; + case 'fault': + return '❌'; + case 'warning': + return '❗'; + case 'hmm': + return '?'; + case 'none': + return '―'; + default: + // should not arrive here + return '??'; + } } } diff --git a/app/common/BootProbe.ts b/app/common/BootProbe.ts index 0da3c859..49fb9911 100644 --- a/app/common/BootProbe.ts +++ b/app/common/BootProbe.ts @@ -13,9 +13,12 @@ export type BootProbeIds = export interface BootProbeResult { verdict?: string; - success?: boolean; - done?: boolean; - severity?: 'fault' | 'warning' | 'hmm'; + // Result of check. + // "success" is a positive outcome. + // "none" means no fault detected (but that the test is not exhaustive + // enough to claim "success"). + // "fault" is a bad error, "warning" a ... warning, "hmm" almost a debug message. + status: 'success' | 'fault' | 'warning' | 'hmm' | 'none'; details?: Record; } diff --git a/app/server/lib/BootProbes.ts b/app/server/lib/BootProbes.ts index 8145f2a2..df9427f2 100644 --- a/app/server/lib/BootProbes.ts +++ b/app/server/lib/BootProbes.ts @@ -91,17 +91,16 @@ const _homeUrlReachableProbe: Probe = { throw new ApiError(await resp.text(), resp.status); } return { - success: true, + status: 'success', details, }; } catch (e) { return { - success: false, details: { ...details, error: String(e), }, - severity: 'fault', + status: 'fault', }; } } @@ -121,7 +120,7 @@ const _webSocketsProbe: Probe = { ws.on('open', () => { ws.send('Just nod if you can hear me.'); resolve({ - success: true, + status: 'success', details, }); ws.close(); @@ -129,7 +128,7 @@ const _webSocketsProbe: Probe = { ws.on('error', (ev) => { details.error = ev.message; resolve({ - success: false, + status: 'fault', details, }); ws.close(); @@ -159,17 +158,16 @@ const _statusCheckProbe: Probe = { throw new Error(`Failed, page has unexpected content`); } return { - success: true, + status: 'success', details, }; } catch (e) { return { - success: false, details: { ...details, error: String(e), }, - severity: 'fault', + status: 'fault', }; } }, @@ -185,13 +183,12 @@ const _userProbe: Probe = { if (process.getuid && process.getuid() === 0) { return { details, - success: false, verdict: 'User appears to be root (UID 0)', - severity: 'warning', + status: 'warning', }; } else { return { - success: true, + status: 'success', details, }; } @@ -208,22 +205,20 @@ const _bootProbe: Probe = { bootKeySet: hasBoot, }; if (!hasBoot) { - return { success: true, details }; + return { status: 'success', details }; } details.bootKeyLength = bootKey.length; if (bootKey.length < 10) { return { - success: false, verdict: 'Boot key length is shorter than 10.', details, - severity: 'fault', + status: 'fault', }; } return { - success: false, verdict: 'Boot key ideally should be removed after installation.', details, - severity: 'warning', + status: 'warning', }; }, }; @@ -247,19 +242,18 @@ const _hostHeaderProbe: Probe = { }; if (url.hostname === 'localhost') { return { - done: true, + status: 'none', details, }; } if (String(url.hostname).toLowerCase() !== String(host).toLowerCase()) { return { - success: false, details, - severity: 'hmm', + status: 'hmm', }; } return { - done: true, + status: 'none', details, }; }, @@ -271,7 +265,7 @@ const _sandboxingProbe: Probe = { apply: async (server, req) => { const details = server.getSandboxInfo(); return { - success: details?.configured && details?.functional, + status: (details?.configured && details?.functional) ? 'success' : 'fault', details, }; }, @@ -283,7 +277,7 @@ const _authenticationProbe: Probe = { apply: async(server, req) => { const loginSystemId = server.getInfo('loginMiddlewareComment'); return { - success: loginSystemId != undefined, + status: (loginSystemId != undefined) ? 'success' : 'fault', details: { loginSystemId, }