fix(striker-ui-api): add prepareHost()

main
Tsu-ba-me 2 years ago
parent 7033b64bb3
commit fcf999b11b
  1. 10
      striker-ui-api/src/lib/accessModule.ts
  2. 4
      striker-ui-api/src/lib/buildCondition.ts
  3. 3
      striker-ui-api/src/lib/consts/REG_EXP_PATTERNS.ts
  4. 1
      striker-ui-api/src/lib/consts/SERVER_PATHS.ts
  5. 6
      striker-ui-api/src/lib/request_handlers/anvil/getAnvil.ts
  6. 4
      striker-ui-api/src/lib/request_handlers/file/getFile.ts
  7. 4
      striker-ui-api/src/lib/request_handlers/host/createHost.ts
  8. 4
      striker-ui-api/src/lib/request_handlers/host/getHost.ts
  9. 145
      striker-ui-api/src/lib/request_handlers/host/prepareHost.ts
  10. 4
      striker-ui-api/src/lib/request_handlers/job/getJob.ts
  11. 4
      striker-ui-api/src/lib/request_handlers/server/getServer.ts
  12. 6
      striker-ui-api/src/lib/request_handlers/server/getServerDetail.ts
  13. 30
      striker-ui-api/src/lib/sanitize.ts
  14. 10
      striker-ui-api/src/types/DBInsertOrUpdateFunctionCommon.d.ts
  15. 9
      striker-ui-api/src/types/DBInsertOrUpdateJobFunction.d.ts
  16. 18
      striker-ui-api/src/types/DBInsertOrUpdateVariableFunction.d.ts

@ -87,6 +87,15 @@ const dbInsertOrUpdateJob = (
subParams: { job_progress, line, ...rest }, subParams: { job_progress, line, ...rest },
}).stdout; }).stdout;
const dbInsertOrUpdateVariable: DBInsertOrUpdateVariableFunction = (
subParams,
{ spawnSyncOptions } = {},
) =>
execModuleSubroutine('insert_or_update_variables', {
spawnSyncOptions,
subParams,
}).stdout;
const dbJobAnvilSyncShared = ( const dbJobAnvilSyncShared = (
jobName: string, jobName: string,
jobData: string, jobData: string,
@ -157,6 +166,7 @@ const getLocalHostUUID = () => {
export { export {
dbInsertOrUpdateJob as job, dbInsertOrUpdateJob as job,
dbInsertOrUpdateVariable as variable,
dbJobAnvilSyncShared, dbJobAnvilSyncShared,
dbQuery, dbQuery,
dbSubRefreshTimestamp, dbSubRefreshTimestamp,

@ -1,6 +1,6 @@
import call from './call'; import call from './call';
import join from './join'; import join from './join';
import { sanitizeQS } from './sanitizeQS'; import { sanitize } from './sanitize';
const buildIDCondition = ( const buildIDCondition = (
keys: Parameters<JoinFunction>[0], keys: Parameters<JoinFunction>[0],
@ -24,7 +24,7 @@ export const buildUnknownIDCondition = (
conditionPrefix: string, conditionPrefix: string,
{ onFallback }: { onFallback?: () => string }, { onFallback }: { onFallback?: () => string },
): { after: string; before: string[] } => { ): { after: string; before: string[] } => {
const before = sanitizeQS(keys, { const before = sanitize(keys, {
modifierType: 'sql', modifierType: 'sql',
returnType: 'string[]', returnType: 'string[]',
}); });

@ -14,6 +14,9 @@ export const REP_IPV4 = new RegExp(`^${ipv4}$`);
export const REP_IPV4_CSV = new RegExp(`(?:${ipv4},)*${ipv4}`); export const REP_IPV4_CSV = new RegExp(`(?:${ipv4},)*${ipv4}`);
// Peaceful string is temporarily defined as a string without single-quote, double-quote, slash (/), backslash (\\), angle brackets (< >), and curly brackets ({ }).
export const REP_PEACEFUL_STRING = /^[^'"/\\><}{]+$/;
export const REP_UUID = new RegExp( export const REP_UUID = new RegExp(
`^${hex}{8}-${hex}{4}-[1-5]${hex}{3}-[89ab]${hex}{3}-${hex}{12}$`, `^${hex}{8}-${hex}{4}-[1-5]${hex}{3}-[89ab]${hex}{3}-${hex}{12}$`,
'i', 'i',

@ -23,6 +23,7 @@ const EMPTY_SERVER_PATHS: ServerPath = {
'anvil-provision-server': {}, 'anvil-provision-server': {},
'anvil-sync-shared': {}, 'anvil-sync-shared': {},
'anvil-update-system': {}, 'anvil-update-system': {},
'striker-initialize-host': {},
'striker-manage-install-target': {}, 'striker-manage-install-target': {},
'striker-parse-os-list': {}, 'striker-parse-os-list': {},
}, },

@ -2,7 +2,7 @@ import { RequestHandler } from 'express';
import buildGetRequestHandler from '../buildGetRequestHandler'; import buildGetRequestHandler from '../buildGetRequestHandler';
import buildQueryAnvilDetail from './buildQueryAnvilDetail'; import buildQueryAnvilDetail from './buildQueryAnvilDetail';
import { sanitizeQS } from '../../sanitizeQS'; import { sanitize } from '../../sanitize';
const getAnvil: RequestHandler = buildGetRequestHandler( const getAnvil: RequestHandler = buildGetRequestHandler(
(request, buildQueryOptions) => { (request, buildQueryOptions) => {
@ -61,11 +61,11 @@ const getAnvil: RequestHandler = buildGetRequestHandler(
query: anvilDetailQuery, query: anvilDetailQuery,
afterQueryReturn: anvilDetailAfterQueryReturn, afterQueryReturn: anvilDetailAfterQueryReturn,
} = buildQueryAnvilDetail({ } = buildQueryAnvilDetail({
anvilUUIDs: sanitizeQS(anvilUUIDs, { anvilUUIDs: sanitize(anvilUUIDs, {
modifierType: 'sql', modifierType: 'sql',
returnType: 'string[]', returnType: 'string[]',
}), }),
isForProvisionServer: sanitizeQS(isForProvisionServer, { isForProvisionServer: sanitize(isForProvisionServer, {
returnType: 'boolean', returnType: 'boolean',
}), }),
}); });

@ -2,7 +2,7 @@ import { RequestHandler } from 'express';
import buildGetRequestHandler from '../buildGetRequestHandler'; import buildGetRequestHandler from '../buildGetRequestHandler';
import buildQueryFileDetail from './buildQueryFileDetail'; import buildQueryFileDetail from './buildQueryFileDetail';
import { sanitizeQS } from '../../sanitizeQS'; import { sanitize } from '../../sanitize';
const getFile: RequestHandler = buildGetRequestHandler((request) => { const getFile: RequestHandler = buildGetRequestHandler((request) => {
const { fileUUIDs } = request.query; const { fileUUIDs } = request.query;
@ -19,7 +19,7 @@ const getFile: RequestHandler = buildGetRequestHandler((request) => {
if (fileUUIDs) { if (fileUUIDs) {
query = buildQueryFileDetail({ query = buildQueryFileDetail({
fileUUIDs: sanitizeQS(fileUUIDs, { fileUUIDs: sanitize(fileUUIDs, {
modifierType: 'sql', modifierType: 'sql',
returnType: 'string[]', returnType: 'string[]',
}), }),

@ -1,7 +1,7 @@
import { RequestHandler } from 'express'; import { RequestHandler } from 'express';
import { configStriker } from './configStriker'; import { configStriker } from './configStriker';
import { sanitizeQS } from '../../sanitizeQS'; import { sanitize } from '../../sanitize';
import { stdout } from '../../shell'; import { stdout } from '../../shell';
// Ensure each create handler sends a response at the end of any branch. // Ensure each create handler sends a response at the end of any branch.
@ -16,7 +16,7 @@ export const createHost: RequestHandler = (...args) => {
}, },
] = args; ] = args;
const hostType = sanitizeQS(rawHostType, { returnType: 'string' }); const hostType = sanitize(rawHostType, { returnType: 'string' });
stdout(`hostType=[${hostType}]`); stdout(`hostType=[${hostType}]`);

@ -2,7 +2,7 @@ import { getLocalHostUUID } from '../../accessModule';
import buildGetRequestHandler from '../buildGetRequestHandler'; import buildGetRequestHandler from '../buildGetRequestHandler';
import { buildQueryHostDetail } from './buildQueryHostDetail'; import { buildQueryHostDetail } from './buildQueryHostDetail';
import { toLocal } from '../../convertHostUUID'; import { toLocal } from '../../convertHostUUID';
import { sanitizeQS } from '../../sanitizeQS'; import { sanitize } from '../../sanitize';
export const getHost = buildGetRequestHandler((request, buildQueryOptions) => { export const getHost = buildGetRequestHandler((request, buildQueryOptions) => {
const { hostUUIDs } = request.query; const { hostUUIDs } = request.query;
@ -37,7 +37,7 @@ export const getHost = buildGetRequestHandler((request, buildQueryOptions) => {
if (hostUUIDs) { if (hostUUIDs) {
({ query, afterQueryReturn } = buildQueryHostDetail({ ({ query, afterQueryReturn } = buildQueryHostDetail({
keys: sanitizeQS(hostUUIDs, { keys: sanitize(hostUUIDs, {
modifierType: 'sql', modifierType: 'sql',
returnType: 'string[]', returnType: 'string[]',
}), }),

@ -0,0 +1,145 @@
import assert from 'assert';
import { RequestHandler } from 'express';
import {
REP_DOMAIN,
REP_IPV4,
REP_PEACEFUL_STRING,
REP_UUID,
} from '../../consts/REG_EXP_PATTERNS';
import SERVER_PATHS from '../../consts/SERVER_PATHS';
import { job, variable } from '../../accessModule';
import { sanitize } from '../../sanitize';
import { stderr } from '../../shell';
export const prepareHost: RequestHandler<
unknown,
undefined,
{
hostIPAddress: string;
hostName: string;
hostPassword: string;
hostSSHPort?: number;
hostType: string;
hostUser?: string;
hostUUID?: string;
redhatPassword: string;
redhatUser: string;
}
> = (request, response) => {
const {
body: {
hostIPAddress,
hostName,
hostPassword,
hostSSHPort,
hostType,
hostUser = 'root',
hostUUID,
redhatPassword,
redhatUser,
} = {},
} = request;
const isHostUUIDProvided = hostUUID !== undefined;
const dataHostIPAddress = sanitize<'string'>(hostIPAddress);
const dataHostName = sanitize<'string'>(hostName);
const dataHostPassword = sanitize<'string'>(hostPassword);
const dataHostSSHPort = sanitize<'number'>(hostSSHPort) || 22;
const dataHostType = sanitize<'string'>(hostType);
const dataHostUser = sanitize<'string'>(hostUser);
const dataHostUUID = sanitize<'string'>(hostUUID);
const dataRedhatPassword = sanitize<'string'>(redhatPassword);
const dataRedhatUser = sanitize<'string'>(redhatUser);
try {
assert(
REP_IPV4.test(dataHostIPAddress),
`Data host IP address must be a valid IPv4 address; got [${dataHostIPAddress}]`,
);
assert(
REP_DOMAIN.test(dataHostName),
`Data host name can only contain alphanumeric, hyphen, and dot characters; got [${dataHostName}]`,
);
assert(
REP_PEACEFUL_STRING.test(dataHostPassword),
`Data host password must be peaceful string; got [${dataHostPassword}]`,
);
assert(
/^node|dr$/.test(dataHostType),
`Data host type must be one of "node" or "dr"; got [${dataHostType}]`,
);
assert(
REP_PEACEFUL_STRING.test(dataHostUser),
`Data host user must be a peaceful string; got [${dataHostUser}]`,
);
if (isHostUUIDProvided) {
assert(
REP_UUID.test(dataHostUUID),
`Data host UUID must be a valid UUIDv4; got [${dataHostUUID}]`,
);
}
assert(
REP_PEACEFUL_STRING.test(dataRedhatPassword),
`Data redhat password must be a peaceful string; got [${dataRedhatPassword}]`,
);
assert(
REP_PEACEFUL_STRING.test(dataRedhatUser),
`Data redhat user must be a peaceful string; got [${dataRedhatUser}]`,
);
} catch (assertError) {
stderr(
`Failed to assert value when trying to prepare host; CAUSE: ${assertError}`,
);
response.status(400).send();
return;
}
try {
if (isHostUUIDProvided) {
variable({
file: __filename,
update_value_only: 1,
variable_name: 'system::configured',
variable_source_table: 'hosts',
variable_source_uuid: dataHostUUID,
variable_value: 0,
});
}
job({
file: __filename,
job_command: SERVER_PATHS.usr.sbin['striker-initialize-host'].self,
job_data: `host_ip_address=${dataHostIPAddress}
host_name=${dataHostName}
password=${dataHostPassword}
rh_password=${dataRedhatPassword}
rh_user=${dataRedhatUser}
ssh_port=${dataHostSSHPort}
type=${dataHostType}`,
job_description: 'job_0022',
job_name: `initialize::${dataHostType}::${dataHostIPAddress}`,
job_progress: 100,
job_title: `job_002${dataHostType === 'dr' ? '1' : '0'}`,
});
} catch (subError) {
stderr(`Failed to init host; CAUSE: ${subError}`);
response.status(500).send();
return;
}
response.status(200).send();
};

@ -1,11 +1,11 @@
import buildGetRequestHandler from '../buildGetRequestHandler'; import buildGetRequestHandler from '../buildGetRequestHandler';
import { sanitizeQS } from '../../sanitizeQS'; import { sanitize } from '../../sanitize';
import { date, stdout } from '../../shell'; import { date, stdout } from '../../shell';
export const getJob = buildGetRequestHandler((request, buildQueryOptions) => { export const getJob = buildGetRequestHandler((request, buildQueryOptions) => {
const { start: rawStart } = request.query; const { start: rawStart } = request.query;
const start = sanitizeQS(rawStart, { returnType: 'number' }); const start = sanitize(rawStart, { returnType: 'number' });
let condModifiedDate = ''; let condModifiedDate = '';

@ -1,13 +1,13 @@
import buildGetRequestHandler from '../buildGetRequestHandler'; import buildGetRequestHandler from '../buildGetRequestHandler';
import join from '../../join'; import join from '../../join';
import { sanitizeQS } from '../../sanitizeQS'; import { sanitize } from '../../sanitize';
export const getServer = buildGetRequestHandler( export const getServer = buildGetRequestHandler(
(request, buildQueryOptions) => { (request, buildQueryOptions) => {
const { anvilUUIDs } = request.query; const { anvilUUIDs } = request.query;
const condAnvilUUIDs = join( const condAnvilUUIDs = join(
sanitizeQS(anvilUUIDs, { returnType: 'string[]' }), sanitize(anvilUUIDs, { returnType: 'string[]' }),
{ {
beforeReturn: (toReturn) => beforeReturn: (toReturn) =>
toReturn ? `AND ser.server_anvil_uuid IN (${toReturn})` : '', toReturn ? `AND ser.server_anvil_uuid IN (${toReturn})` : '',

@ -7,7 +7,7 @@ import { REP_UUID } from '../../consts/REG_EXP_PATTERNS';
import SERVER_PATHS from '../../consts/SERVER_PATHS'; import SERVER_PATHS from '../../consts/SERVER_PATHS';
import { dbQuery, getLocalHostUUID, job } from '../../accessModule'; import { dbQuery, getLocalHostUUID, job } from '../../accessModule';
import { sanitizeQS } from '../../sanitizeQS'; import { sanitize } from '../../sanitize';
import { mkfifo, rm } from '../../shell'; import { mkfifo, rm } from '../../shell';
export const getServerDetail: RequestHandler = (request, response) => { export const getServerDetail: RequestHandler = (request, response) => {
@ -15,7 +15,7 @@ export const getServerDetail: RequestHandler = (request, response) => {
const { ss, resize } = request.query; const { ss, resize } = request.query;
const epoch = Date.now(); const epoch = Date.now();
const isScreenshot = sanitizeQS(ss, { const isScreenshot = sanitize(ss, {
returnType: 'boolean', returnType: 'boolean',
}); });
@ -118,7 +118,7 @@ export const getServerDetail: RequestHandler = (request, response) => {
return; return;
} }
let resizeArgs = sanitizeQS(resize, { let resizeArgs = sanitize(resize, {
returnType: 'string', returnType: 'string',
}); });

@ -10,12 +10,12 @@ type MapToReturnType = {
type MapToReturnFunction = { type MapToReturnFunction = {
[ReturnTypeName in keyof MapToReturnType]: ( [ReturnTypeName in keyof MapToReturnType]: (
qs: unknown, value: unknown,
modifier: (value: unknown) => string, modifier: (unmodified: unknown) => string,
) => MapToReturnType[ReturnTypeName]; ) => MapToReturnType[ReturnTypeName];
}; };
type ModifierFunction = (value: string) => string; type ModifierFunction = (unmodified: string) => string;
type MapToModifierFunction = { type MapToModifierFunction = {
none: undefined; none: undefined;
@ -28,30 +28,30 @@ const MAP_TO_MODIFIER_FUNCTION: MapToModifierFunction = {
}; };
const MAP_TO_RETURN_FUNCTION: MapToReturnFunction = { const MAP_TO_RETURN_FUNCTION: MapToReturnFunction = {
boolean: (qs) => qs !== undefined, boolean: (value) => value !== undefined,
number: (qs) => parseFloat(String(qs)) || 0, number: (value) => parseFloat(String(value)) || 0,
string: (qs, mod) => (qs ? mod(qs) : ''), string: (value, mod) => (value ? mod(value) : ''),
'string[]': (qs, mod) => { 'string[]': (value, mod) => {
let result: string[] = []; let result: string[] = [];
if (qs instanceof Array) { if (value instanceof Array) {
result = qs.reduce<string[]>((reduceContainer, element) => { result = value.reduce<string[]>((reduceContainer, element) => {
if (element) { if (element) {
reduceContainer.push(mod(element)); reduceContainer.push(mod(element));
} }
return reduceContainer; return reduceContainer;
}, []); }, []);
} else if (qs) { } else if (value) {
result = mod(qs).split(/[,;]/); result = mod(value).split(/[,;]/);
} }
return result; return result;
}, },
}; };
export const sanitizeQS = <ReturnTypeName extends keyof MapToReturnType>( export const sanitize = <ReturnTypeName extends keyof MapToReturnType>(
qs: unknown, value: unknown,
{ {
modifierType = 'none', modifierType = 'none',
modifier = MAP_TO_MODIFIER_FUNCTION[modifierType], modifier = MAP_TO_MODIFIER_FUNCTION[modifierType],
@ -62,8 +62,8 @@ export const sanitizeQS = <ReturnTypeName extends keyof MapToReturnType>(
returnType?: ReturnTypeName | 'string'; returnType?: ReturnTypeName | 'string';
} = {}, } = {},
): MapToReturnType[ReturnTypeName] => ): MapToReturnType[ReturnTypeName] =>
MAP_TO_RETURN_FUNCTION[returnType](qs, (value: unknown) => { MAP_TO_RETURN_FUNCTION[returnType](value, (unmodified: unknown) => {
const input = String(value); const input = String(unmodified);
return call<string>(modifier, { return call<string>(modifier, {
notCallableReturn: input, notCallableReturn: input,

@ -0,0 +1,10 @@
type DBInsertOrUpdateFunctionCommonParams = {
debug?: number;
file: string;
line?: number;
};
type DBInsertOrUpdateFunctionCommonOptions = Omit<
ExecModuleSubroutineOptions,
'subParams' | 'subModuleName'
>;

@ -1,6 +1,4 @@
type DBJobParams = { type DBJobParams = DBInsertOrUpdateFunctionCommonParams & {
file: string;
line?: number;
job_command: string; job_command: string;
job_data?: string; job_data?: string;
job_name: string; job_name: string;
@ -10,7 +8,4 @@ type DBJobParams = {
job_progress?: number; job_progress?: number;
}; };
type DBInsertOrUpdateJobOptions = Omit< type DBInsertOrUpdateJobOptions = DBInsertOrUpdateFunctionCommonOptions;
ExecModuleSubroutineOptions,
'subParams' | 'subModuleName'
>;

@ -0,0 +1,18 @@
type DBVariableParams = DBInsertOrUpdateFunctionCommonParams & {
update_value_only?: 0 | 1;
variable_default?: string;
varaible_description?: string;
variable_name?: string;
variable_section?: string;
variable_source_table?: string;
variable_source_uuid?: string;
variable_uuid?: string;
variable_value?: number | string;
};
type DBInsertOrUpdateVariableOptions = DBInsertOrUpdateFunctionCommonOptions;
type DBInsertOrUpdateVariableFunction = (
subParams: DBVariableParams,
options?: DBInsertOrUpdateVariableOptions,
) => string;
Loading…
Cancel
Save