From 8403d7315b289d460a440887aa108de42580d991 Mon Sep 17 00:00:00 2001 From: Tsu-ba-me Date: Thu, 22 Jun 2023 00:49:19 -0400 Subject: [PATCH] fix(striker-ui-api): assert host configured before authentication --- striker-ui-api/src/middlewares/assertInit.ts | 55 ++++++++++++++ striker-ui-api/src/middlewares/index.ts | 1 + striker-ui-api/src/routes/init.ts | 36 +-------- striker-ui-api/src/routes/static.ts | 78 ++++++++++++-------- 4 files changed, 106 insertions(+), 64 deletions(-) create mode 100644 striker-ui-api/src/middlewares/assertInit.ts diff --git a/striker-ui-api/src/middlewares/assertInit.ts b/striker-ui-api/src/middlewares/assertInit.ts new file mode 100644 index 00000000..ada794fa --- /dev/null +++ b/striker-ui-api/src/middlewares/assertInit.ts @@ -0,0 +1,55 @@ +import { Handler } from 'express'; + +import { LOCAL } from '../lib/consts'; + +import { query } from '../lib/accessModule'; +import { toHostUUID } from '../lib/convertHostUUID'; +import { stderr, stdoutVar } from '../lib/shell'; + +export const assertInit = + ({ + fail = (rq, rs) => rs.status(401).send(), + hostUuid: rHostUuid = LOCAL, + invert, + succeed = (rq, rs, nx) => nx(), + }: { + fail?: (...args: Parameters) => void; + hostUuid?: string; + invert?: boolean; + succeed?: (...args: Parameters) => void; + } = {}): Handler => + async (...args) => { + const { 1: response } = args; + const hostUuid = toHostUUID(rHostUuid); + + let rows: [[string]]; + + try { + rows = await query( + `SELECT variable_value + FROM variables + WHERE variable_name = 'system::configured' + AND variable_source_table = 'hosts' + AND variable_source_uuid = '${hostUuid}' + LIMIT 1;`, + ); + } catch (error) { + stderr(`Failed to get system configured flag; CAUSE: ${error}`); + + return response.status(500).send(); + } + + stdoutVar(rows, `Configured variable of host ${hostUuid}: `); + + let condition = rows.length === 1 && rows[0][0] === '1'; + + if (invert) condition = !condition; + + if (condition) { + stderr(`Assert init failed; invert=${invert}`); + + return fail(...args); + } + + return succeed(...args); + }; diff --git a/striker-ui-api/src/middlewares/index.ts b/striker-ui-api/src/middlewares/index.ts index 5cc3dad9..2020c48d 100644 --- a/striker-ui-api/src/middlewares/index.ts +++ b/striker-ui-api/src/middlewares/index.ts @@ -2,5 +2,6 @@ import passport from './passport'; import session from './session'; export * from './assertAuthentication'; +export * from './assertInit'; export { passport, session }; diff --git a/striker-ui-api/src/routes/init.ts b/striker-ui-api/src/routes/init.ts index 58ba8578..e42e11ad 100644 --- a/striker-ui-api/src/routes/init.ts +++ b/striker-ui-api/src/routes/init.ts @@ -1,7 +1,6 @@ import express from 'express'; -import { getLocalHostUUID, query } from '../lib/accessModule'; -import { stderr, stdoutVar } from '../lib/shell'; +import { assertInit } from '../middlewares'; import { setMapNetwork } from '../lib/request_handlers/command'; import { configStriker } from '../lib/request_handlers/host'; @@ -9,38 +8,7 @@ import { getNetworkInterface } from '../lib/request_handlers/network-interface'; const router = express.Router(); -router.use(async (request, response, next) => { - const localHostUuid = getLocalHostUUID(); - - let rows: [[string]]; - - try { - rows = await query( - `SELECT variable_value - FROM variables - WHERE variable_name = 'system::configured' - AND variable_source_table = 'hosts' - AND variable_source_uuid = '${localHostUuid}' - LIMIT 1;`, - ); - } catch (error) { - stderr(`Failed to get system configured flag; CAUSE: ${error}`); - - return response.status(500).send(); - } - - stdoutVar(rows, `system::configured=`); - - if (rows.length === 1 && rows[0][0] === '1') { - stderr( - `The init endpoints cannot be used after initializing the local striker`, - ); - - return response.status(401).send(); - } - - return next(); -}); +router.use(assertInit()); router .get('/network-interface', getNetworkInterface) diff --git a/striker-ui-api/src/routes/static.ts b/striker-ui-api/src/routes/static.ts index 32bc786b..d3ea0df1 100644 --- a/striker-ui-api/src/routes/static.ts +++ b/striker-ui-api/src/routes/static.ts @@ -1,52 +1,70 @@ import express from 'express'; import { existsSync } from 'fs'; -import path from 'path'; import { SERVER_PATHS } from '../lib/consts'; -import { assertAuthentication } from '../middlewares'; +import { assertAuthentication, assertInit } from '../middlewares'; import { stdout } from '../lib/shell'; const router = express.Router(); const htmlDir = SERVER_PATHS.var.www.html.self; -router.use( - (...args) => { - const { 0: request, 2: next } = args; - const { originalUrl } = request; +router.use((...args) => { + const [request, response, next] = args; + const { originalUrl, path: initialPath } = request; - if (/^[/]login/.test(originalUrl)) { - stdout(`Static:login requested`); + console.log(`originalUrl=${originalUrl},initialpath=${initialPath}`); - return assertAuthentication({ - fail: (rt, rq, rs, nx) => nx(), - succeed: '/', - })(...args); + let path = initialPath; + + if (path.slice(-1) === '/') { + if (path.length > 1) { + const q = originalUrl.slice(path.length); + const p = path.slice(0, -1).replace(/\/+/g, '/'); + const t = `${p}${q}`; + + console.log(`redirect=${t}`); + + return response.redirect(t); + } else { + path = '/index'; } + } - const parts = originalUrl.replace(/[/]$/, '').split('/'); - const tail = parts.pop() || 'index'; - const extended = /[.]html$/.test(tail) ? tail : `${tail}.html`; + const exted = /\.html$/.test(path) ? path : `${path}.html`; + const fpath = `${htmlDir}${exted}`; + const htmlExists = existsSync(fpath); - parts.push(extended); + stdout(`static:[${path}] requested; html=${htmlExists}`); - const htmlPath = path.posix.join(htmlDir, ...parts); - const isHtmlExists = existsSync(htmlPath); + // Request for asset, i.e., image, script. + if (!htmlExists) return next(); - if (isHtmlExists) { - stdout(`Static:[${htmlPath}] requested`); + return assertInit({ + // When not configured, redirect to the init page. + fail: (rq, rs, nx) => { + const { path: p } = rq; + const target = '/init'; - return assertAuthentication({ fail: '/login', failReturnTo: true })( - ...args, - ); - } + if (p.startsWith(target)) return nx(); + + return rs.redirect(target); + }, + invert: true, + // When configured, check whether user is authenticated. + succeed: assertAuthentication({ + fail: (rt, rq, rs, nx) => { + const { path: p } = rq; + const target = '/login'; + + if (p.startsWith(target)) return nx(); - return next(); - }, - express.static(htmlDir, { - extensions: ['htm', 'html'], - }), -); + return rs.redirect(rt ? `${target}?rt=${rt}` : target); + }, + failReturnTo: !path.startsWith('/login'), + }), + })(...args); +}, express.static(htmlDir, { extensions: ['html'] })); export default router;