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 },
}).stdout;
const dbInsertOrUpdateVariable: DBInsertOrUpdateVariableFunction = (
subParams,
{ spawnSyncOptions } = {},
) =>
execModuleSubroutine('insert_or_update_variables', {
spawnSyncOptions,
subParams,
}).stdout;
const dbJobAnvilSyncShared = (
jobName: string,
jobData: string,
@ -157,6 +166,7 @@ const getLocalHostUUID = () => {
export {
dbInsertOrUpdateJob as job,
dbInsertOrUpdateVariable as variable,
dbJobAnvilSyncShared,
dbQuery,
dbSubRefreshTimestamp,

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

@ -14,6 +14,9 @@ export const REP_IPV4 = new RegExp(`^${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(
`^${hex}{8}-${hex}{4}-[1-5]${hex}{3}-[89ab]${hex}{3}-${hex}{12}$`,
'i',

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

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

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

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

@ -2,7 +2,7 @@ import { getLocalHostUUID } from '../../accessModule';
import buildGetRequestHandler from '../buildGetRequestHandler';
import { buildQueryHostDetail } from './buildQueryHostDetail';
import { toLocal } from '../../convertHostUUID';
import { sanitizeQS } from '../../sanitizeQS';
import { sanitize } from '../../sanitize';
export const getHost = buildGetRequestHandler((request, buildQueryOptions) => {
const { hostUUIDs } = request.query;
@ -37,7 +37,7 @@ export const getHost = buildGetRequestHandler((request, buildQueryOptions) => {
if (hostUUIDs) {
({ query, afterQueryReturn } = buildQueryHostDetail({
keys: sanitizeQS(hostUUIDs, {
keys: sanitize(hostUUIDs, {
modifierType: 'sql',
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 { sanitizeQS } from '../../sanitizeQS';
import { sanitize } from '../../sanitize';
import { date, stdout } from '../../shell';
export const getJob = buildGetRequestHandler((request, buildQueryOptions) => {
const { start: rawStart } = request.query;
const start = sanitizeQS(rawStart, { returnType: 'number' });
const start = sanitize(rawStart, { returnType: 'number' });
let condModifiedDate = '';

@ -1,13 +1,13 @@
import buildGetRequestHandler from '../buildGetRequestHandler';
import join from '../../join';
import { sanitizeQS } from '../../sanitizeQS';
import { sanitize } from '../../sanitize';
export const getServer = buildGetRequestHandler(
(request, buildQueryOptions) => {
const { anvilUUIDs } = request.query;
const condAnvilUUIDs = join(
sanitizeQS(anvilUUIDs, { returnType: 'string[]' }),
sanitize(anvilUUIDs, { returnType: 'string[]' }),
{
beforeReturn: (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 { dbQuery, getLocalHostUUID, job } from '../../accessModule';
import { sanitizeQS } from '../../sanitizeQS';
import { sanitize } from '../../sanitize';
import { mkfifo, rm } from '../../shell';
export const getServerDetail: RequestHandler = (request, response) => {
@ -15,7 +15,7 @@ export const getServerDetail: RequestHandler = (request, response) => {
const { ss, resize } = request.query;
const epoch = Date.now();
const isScreenshot = sanitizeQS(ss, {
const isScreenshot = sanitize(ss, {
returnType: 'boolean',
});
@ -118,7 +118,7 @@ export const getServerDetail: RequestHandler = (request, response) => {
return;
}
let resizeArgs = sanitizeQS(resize, {
let resizeArgs = sanitize(resize, {
returnType: 'string',
});

@ -10,12 +10,12 @@ type MapToReturnType = {
type MapToReturnFunction = {
[ReturnTypeName in keyof MapToReturnType]: (
qs: unknown,
modifier: (value: unknown) => string,
value: unknown,
modifier: (unmodified: unknown) => string,
) => MapToReturnType[ReturnTypeName];
};
type ModifierFunction = (value: string) => string;
type ModifierFunction = (unmodified: string) => string;
type MapToModifierFunction = {
none: undefined;
@ -28,30 +28,30 @@ const MAP_TO_MODIFIER_FUNCTION: MapToModifierFunction = {
};
const MAP_TO_RETURN_FUNCTION: MapToReturnFunction = {
boolean: (qs) => qs !== undefined,
number: (qs) => parseFloat(String(qs)) || 0,
string: (qs, mod) => (qs ? mod(qs) : ''),
'string[]': (qs, mod) => {
boolean: (value) => value !== undefined,
number: (value) => parseFloat(String(value)) || 0,
string: (value, mod) => (value ? mod(value) : ''),
'string[]': (value, mod) => {
let result: string[] = [];
if (qs instanceof Array) {
result = qs.reduce<string[]>((reduceContainer, element) => {
if (value instanceof Array) {
result = value.reduce<string[]>((reduceContainer, element) => {
if (element) {
reduceContainer.push(mod(element));
}
return reduceContainer;
}, []);
} else if (qs) {
result = mod(qs).split(/[,;]/);
} else if (value) {
result = mod(value).split(/[,;]/);
}
return result;
},
};
export const sanitizeQS = <ReturnTypeName extends keyof MapToReturnType>(
qs: unknown,
export const sanitize = <ReturnTypeName extends keyof MapToReturnType>(
value: unknown,
{
modifierType = 'none',
modifier = MAP_TO_MODIFIER_FUNCTION[modifierType],
@ -62,8 +62,8 @@ export const sanitizeQS = <ReturnTypeName extends keyof MapToReturnType>(
returnType?: ReturnTypeName | 'string';
} = {},
): MapToReturnType[ReturnTypeName] =>
MAP_TO_RETURN_FUNCTION[returnType](qs, (value: unknown) => {
const input = String(value);
MAP_TO_RETURN_FUNCTION[returnType](value, (unmodified: unknown) => {
const input = String(unmodified);
return call<string>(modifier, {
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 = {
file: string;
line?: number;
type DBJobParams = DBInsertOrUpdateFunctionCommonParams & {
job_command: string;
job_data?: string;
job_name: string;
@ -10,7 +8,4 @@ type DBJobParams = {
job_progress?: number;
};
type DBInsertOrUpdateJobOptions = Omit<
ExecModuleSubroutineOptions,
'subParams' | 'subModuleName'
>;
type DBInsertOrUpdateJobOptions = DBInsertOrUpdateFunctionCommonOptions;

@ -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