parent
492983d7ad
commit
0774c80703
12 changed files with 398 additions and 0 deletions
@ -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(); |
||||
}; |
@ -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…
Reference in new issue