feat(striker-ui-api): add /mail-server routes

main
Tsu-ba-me 12 months ago
parent 492983d7ad
commit 0774c80703
  1. 1
      striker-ui-api/src/lib/consts/SERVER_PATHS.ts
  2. 35
      striker-ui-api/src/lib/request_handlers/mail-server/createMailServer.ts
  3. 23
      striker-ui-api/src/lib/request_handlers/mail-server/deleteMailServer.ts
  4. 83
      striker-ui-api/src/lib/request_handlers/mail-server/execManageAlerts.ts
  5. 39
      striker-ui-api/src/lib/request_handlers/mail-server/getMailServer.ts
  6. 68
      striker-ui-api/src/lib/request_handlers/mail-server/getMailServerDetail.ts
  7. 56
      striker-ui-api/src/lib/request_handlers/mail-server/getMailServerRequestBody.ts
  8. 5
      striker-ui-api/src/lib/request_handlers/mail-server/index.ts
  9. 43
      striker-ui-api/src/lib/request_handlers/mail-server/updateMailServer.ts
  10. 2
      striker-ui-api/src/routes/index.ts
  11. 20
      striker-ui-api/src/routes/mail-server.ts
  12. 23
      striker-ui-api/src/types/ApiMailServer.d.ts

@ -34,6 +34,7 @@ const EMPTY_SERVER_PATHS: ServerPath = {
'anvil-delete-server': {},
'anvil-get-server-screenshot': {},
'anvil-join-anvil': {},
'anvil-manage-alerts': {},
'anvil-manage-keys': {},
'anvil-manage-power': {},
'anvil-provision-server': {},

@ -0,0 +1,35 @@
import { RequestHandler } from 'express';
import { execManageAlerts } from './execManageAlerts';
import { getMailServerRequestBody } from './getMailServerRequestBody';
import { stderr, stdout } from '../../shell';
export const createMailServer: RequestHandler<
undefined,
undefined,
MailServerRequestBody
> = (request, response) => {
const { body: rBody = {} } = request;
stdout('Begin creating mail server.');
let body: MailServerRequestBody;
try {
body = getMailServerRequestBody(rBody);
} catch (error) {
stderr(`Failed to process mail server input; CAUSE: ${error}`);
return response.status(400).send();
}
try {
execManageAlerts('mail-servers', 'add', { body });
} catch (error) {
stderr(`Failed to create mail server; CAUSE: ${error}`);
return response.status(500).send();
}
return response.status(201).send();
};

@ -0,0 +1,23 @@
import { RequestHandler } from 'express';
import { execManageAlerts } from './execManageAlerts';
import { stderr } from '../../shell';
export const deleteMailServer: RequestHandler<MailServerParamsDictionary> = (
request,
response,
) => {
const {
params: { uuid },
} = request;
try {
execManageAlerts('mail-servers', 'delete', { uuid });
} catch (error) {
stderr(`Failed to delete mail server; CAUSE: ${error}`);
return response.status(500).send();
}
return response.status(204).send();
};

@ -0,0 +1,83 @@
import assert from 'assert';
import { spawnSync } from 'child_process';
import { SERVER_PATHS } from '../../consts';
import { stdoutVar } from '../../shell';
const MAP_TO_FLAG_BUNDLE = {
'alert-overrides': {},
'mail-servers': {
'--mail-server-address': 'address',
'--mail-server-authentication': 'authentication',
'--mail-server-helo-domain': 'heloDomain',
'--mail-server-password': 'password',
'--mail-server-port': 'port',
'--mail-server-security': 'security',
'--mail-server-username': 'username',
'--mail-server-uuid': 'uuid',
},
recipients: {},
};
export const execManageAlerts = (
entities: 'alert-overrides' | 'mail-servers' | 'recipients',
operation: 'add' | 'edit' | 'delete',
{
body,
uuid,
}: {
body?: Record<string, unknown>;
uuid?: string;
} = {},
) => {
const shallow = { ...body };
if (uuid) {
shallow.uuid = uuid;
}
const commandArgs: string[] = Object.entries(
MAP_TO_FLAG_BUNDLE[entities],
).reduce(
(previous, [flag, key]) => {
const value = shallow[key];
if (value) {
previous.push(flag, String(value));
}
return previous;
},
[`--${entities}`, `--${operation}`, '--yes'],
);
stdoutVar({ commandArgs }, 'Manage alerts with args: ');
try {
const { error, signal, status, stderr, stdout } = spawnSync(
SERVER_PATHS.usr.sbin['anvil-manage-alerts'].self,
commandArgs,
{ encoding: 'utf-8', timeout: 10000 },
);
stdoutVar(
{ error, signal, status, stderr, stdout },
'Manage alerts returned: ',
);
assert.strictEqual(
status,
0,
`Expected status to be 0, but got [${status}]`,
);
assert.strictEqual(
error,
undefined,
`Expected no error, but got [${error}]`,
);
} catch (error) {
throw new Error(`Failed to complete manage alerts; CAUSE: ${error}`);
}
};

@ -0,0 +1,39 @@
import { RequestHandler } from 'express';
import { DELETED } from '../../consts';
import buildGetRequestHandler from '../buildGetRequestHandler';
import { buildQueryResultReducer } from '../../buildQueryResultModifier';
export const getMailServer: RequestHandler = buildGetRequestHandler(
(request, options) => {
const query = `
SELECT
a.mail_server_uuid,
a.mail_server_address,
a.mail_server_port
FROM mail_servers AS a
WHERE a.mail_server_helo_domain != '${DELETED}'
ORDER BY a.mail_server_address;`;
const afterQueryReturn: QueryResultModifierFunction =
buildQueryResultReducer<MailServerOverviewList>(
(previous, [uuid, address, port]) => {
previous[uuid] = {
address,
port: Number(port),
uuid,
};
return previous;
},
{},
);
if (options) {
options.afterQueryReturn = afterQueryReturn;
}
return query;
},
);

@ -0,0 +1,68 @@
import { RequestHandler } from 'express';
import { DELETED } from '../../consts';
import buildGetRequestHandler from '../buildGetRequestHandler';
import { buildQueryResultModifier } from '../../buildQueryResultModifier';
import { sanitize } from '../../sanitize';
export const getMailServerDetail: RequestHandler<MailServerParamsDictionary> =
buildGetRequestHandler((request, options) => {
const {
params: { uuid: rUuid },
} = request;
const uuid = sanitize(rUuid, 'string', { modifierType: 'sql' });
const query = `
SELECT
a.mail_server_uuid,
a.mail_server_address,
a.mail_server_port,
a.mail_server_username,
a.mail_server_password,
a.mail_server_security,
a.mail_server_authentication,
a.mail_server_helo_domain
FROM mail_servers AS a
WHERE a.mail_server_helo_domain != '${DELETED}'
AND a.mail_server_uuid = '${uuid}'
ORDER BY a.mail_server_address ASC;`;
const afterQueryReturn: QueryResultModifierFunction =
buildQueryResultModifier<MailServerDetail | undefined>((rows) => {
if (!rows.length) {
return undefined;
}
const {
0: [
uuid,
address,
port,
username,
password,
security,
authentication,
heloDomain,
],
} = rows;
return {
address,
authentication,
heloDomain,
password,
port: Number(port),
security,
username,
uuid,
};
});
if (options) {
options.afterQueryReturn = afterQueryReturn;
}
return query;
});

@ -0,0 +1,56 @@
import assert from 'assert';
import { sanitize } from '../../sanitize';
export const getMailServerRequestBody = (
body: Partial<MailServerRequestBody>,
): MailServerRequestBody => {
const {
address: rAddress,
authentication: rAuthentication,
heloDomain: rHeloDomain,
password: rPassword,
port: rPort,
security: rSecurity,
username: rUsername,
} = body;
const address = sanitize(rAddress, 'string');
const authentication = sanitize(rAuthentication, 'string', {
fallback: 'none',
});
const heloDomain = sanitize(rHeloDomain, 'string');
const password = sanitize(rPassword, 'string');
const port = sanitize(rPort, 'number', { fallback: 587 });
const security = sanitize(rSecurity, 'string', { fallback: 'none' });
const username = sanitize(rUsername, 'string');
assert.ok(address.length, `Expected address; got [${address}]`);
assert(
['none', 'plain-text', 'encrypted'].includes(authentication),
`Expected authentication to be 'none', 'plain-text', or 'encrypted'; got [${authentication}]`,
);
assert.ok(heloDomain.length, `Expected HELO domain; got [${heloDomain}]`);
assert(
Number.isSafeInteger(port),
`Expected port to be an integer; got [${port}]`,
);
assert(
['none', 'starttls', 'tls-ssl'].includes(security),
`Expected security to be 'none', 'starttls', or 'tls-ssl'; got [${security}]`,
);
return {
address,
authentication,
heloDomain,
password,
port,
security,
username,
};
};

@ -0,0 +1,5 @@
export * from './createMailServer';
export * from './deleteMailServer';
export * from './getMailServer';
export * from './getMailServerDetail';
export * from './updateMailServer';

@ -0,0 +1,43 @@
import assert from 'assert';
import { RequestHandler } from 'express';
import { REP_UUID } from '../../consts';
import { execManageAlerts } from './execManageAlerts';
import { getMailServerRequestBody } from './getMailServerRequestBody';
import { stderr, stdout } from '../../shell';
export const updateMailServer: RequestHandler<
MailServerParamsDictionary,
undefined,
MailServerRequestBody
> = (request, response) => {
const {
body: rBody = {},
params: { uuid },
} = request;
stdout('Begin updating mail server.');
let body: MailServerRequestBody;
try {
assert(REP_UUID.test(uuid), `Expected valid UUIDv4; got [${uuid}]`);
body = getMailServerRequestBody(rBody);
} catch (error) {
stderr(`Failed to process mail server input; CAUSE: ${error}`);
return response.status(400).send();
}
try {
execManageAlerts('mail-servers', 'edit', { body, uuid });
} catch (error) {
stderr(`Failed to update mail server; CAUSE: ${error}`);
return response.status(500).send();
}
return response.status(200).send();
};

@ -7,6 +7,7 @@ import fileRouter from './file';
import hostRouter from './host';
import initRouter from './init';
import jobRouter from './job';
import mailServerRouter from './mail-server';
import manifestRouter from './manifest';
import networkInterfaceRouter from './network-interface';
import serverRouter from './server';
@ -23,6 +24,7 @@ const routes = {
file: fileRouter,
host: hostRouter,
job: jobRouter,
'mail-server': mailServerRouter,
manifest: manifestRouter,
'network-interface': networkInterfaceRouter,
server: serverRouter,

@ -0,0 +1,20 @@
import express from 'express';
import {
createMailServer,
deleteMailServer,
getMailServer,
getMailServerDetail,
updateMailServer,
} from '../lib/request_handlers/mail-server';
const router = express.Router();
router
.delete('/:uuid', deleteMailServer)
.get('/', getMailServer)
.get('/:uuid', getMailServerDetail)
.post('/', createMailServer)
.put('/:uuid', updateMailServer);
export default router;

@ -0,0 +1,23 @@
type MailServerOverview = {
address: string;
port: number;
uuid: string;
};
type MailServerDetail = MailServerOverview & {
authentication: string;
heloDomain: string;
password?: string;
security: string;
username?: string;
};
type MailServerOverviewList = {
[uuid: string]: MailServerOverview;
};
type MailServerParamsDictionary = {
uuid: string;
};
type MailServerRequestBody = Omit<MailServerDetail, 'uuid'>;
Loading…
Cancel
Save