updates, use param handler

This commit is contained in:
Evert Prants 2021-09-04 10:59:56 +03:00
parent 0cb08ca596
commit 6724e8724a
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
5 changed files with 70 additions and 63 deletions

57
package-lock.json generated
View File

@ -5,6 +5,7 @@
"requires": true,
"packages": {
"": {
"name": "icydns",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
@ -14,11 +15,11 @@
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/cors": "^2.8.10",
"@types/express": "^4.17.11",
"@types/node": "^15.3.0",
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/node": "^16.7.10",
"@types/uuid": "^8.3.1",
"typescript": "^4.2.4"
"typescript": "^4.4.2"
}
},
"node_modules/@types/body-parser": {
@ -41,15 +42,15 @@
}
},
"node_modules/@types/cors": {
"version": "2.8.10",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz",
"integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==",
"version": "2.8.12",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==",
"dev": true
},
"node_modules/@types/express": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz",
"integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==",
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
"dev": true,
"dependencies": {
"@types/body-parser": "*",
@ -76,9 +77,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "15.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz",
"integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==",
"version": "16.7.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.10.tgz",
"integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==",
"dev": true
},
"node_modules/@types/qs": {
@ -589,9 +590,9 @@
}
},
"node_modules/typescript": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
"integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@ -655,15 +656,15 @@
}
},
"@types/cors": {
"version": "2.8.10",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz",
"integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==",
"version": "2.8.12",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==",
"dev": true
},
"@types/express": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz",
"integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==",
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
"dev": true,
"requires": {
"@types/body-parser": "*",
@ -690,9 +691,9 @@
"dev": true
},
"@types/node": {
"version": "15.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz",
"integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==",
"version": "16.7.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.10.tgz",
"integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==",
"dev": true
},
"@types/qs": {
@ -1095,9 +1096,9 @@
}
},
"typescript": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
"integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
"dev": true
},
"unpipe": {

View File

@ -19,10 +19,10 @@
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/cors": "^2.8.10",
"@types/express": "^4.17.11",
"@types/node": "^15.3.0",
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/node": "^16.7.10",
"@types/uuid": "^8.3.1",
"typescript": "^4.2.4"
"typescript": "^4.4.2"
}
}

View File

@ -87,12 +87,12 @@ export class DNSCache {
try {
await this.validator.validateAndSave(name, zone);
} catch (e) {
} catch (e: any) {
// Reload previous state
if (e.message.contains('Validation')) {
await this.load(name, zone.file);
}
throw e;
throw e as Error;
}
}
@ -122,8 +122,8 @@ export class DNSCache {
if (!skipReload) {
try {
await this.rndc.reload(name);
} catch (e) {
logger.warn('%s automatic zone reload failed:', name, e.stack);
} catch (e: unknown) {
logger.warn('%s automatic zone reload failed:', name, (e as Error).stack);
}
}
}

View File

@ -1,4 +1,10 @@
import express, { ErrorRequestHandler, NextFunction, Request, RequestHandler, Response } from 'express';
import express, {
ErrorRequestHandler,
NextFunction,
Request,
RequestHandler,
Response
} from 'express';
import cors from 'cors';
import 'express-async-errors';
import path from 'path';
@ -20,7 +26,7 @@ const dir = process.env.ZONEFILES || '.';
const app = express();
const api = express.Router();
app.use(express.json());
app.use(express.json() as RequestHandler);
app.enable('trust proxy');
app.use(cors({
@ -73,12 +79,13 @@ api.use((req, res, next) => {
});
const domainAuthorization: RequestHandler = (req, res, next) => {
if (!req.params.domain || !res.locals.token) {
const domain = res.locals.domain || req.params.domain;
if (!domain || !res.locals.token) {
next(new Error('Unexpected bad request'));
return;
}
if (keys.getDomain(res.locals.token) !== req.params.domain) {
if (keys.getDomain(res.locals.token) !== domain) {
res.status(401).json({ success: false, message: 'Unauthorized access to domain' });
return;
}
@ -86,12 +93,18 @@ const domainAuthorization: RequestHandler = (req, res, next) => {
next();
}
api.param('domain', async (_req, res, next, id) => {
const cached = await getOrLoad(id);
res.locals.cached = cached;
res.locals.domain = id;
next();
});
/**
* Get zone records
*/
api.get('/zone/records/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const cached = await getOrLoad(domain);
const { cached } = res.locals;
const type = req.query.type as DNSRecordType;
const name = req.query.name as string;
@ -120,7 +133,7 @@ api.get('/zone/records/:domain', domainAuthorization, async (req, res) => {
* }[];
*/
api.patch('/zone/records/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const { domain, cached } = res.locals;
let setters = req.body.record;
if (!setters) {
@ -132,8 +145,7 @@ api.patch('/zone/records/:domain', domainAuthorization, async (req, res) => {
setters = [setters];
}
const cached = await getOrLoad(domain);
const { zone } = cached;
const { zone } = cached as CachedZone;
const changed = [];
const errors = [];
@ -237,11 +249,10 @@ api.patch('/zone/records/:domain', domainAuthorization, async (req, res) => {
* index: number;
*/
api.delete('/zone/records/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const { domain, cached } = res.locals;
let indexes = req.body.index;
const cached = await getOrLoad(domain);
const { zone } = cached;
const { zone } = cached as CachedZone;
if (!Array.isArray(indexes)) {
indexes = [indexes];
@ -296,7 +307,7 @@ api.delete('/zone/records/:domain', domainAuthorization, async (req, res) => {
* }[];
*/
api.post('/zone/records/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const { domain, cached } = res.locals;
let setters = req.body.record;
if (!setters) {
@ -307,8 +318,7 @@ api.post('/zone/records/:domain', domainAuthorization, async (req, res) => {
setters = [setters];
}
const cached = await getOrLoad(domain);
const { zone } = cached;
const { zone } = cached as CachedZone;
const created = [];
const errors = [];
@ -397,8 +407,7 @@ api.post('/zone/records/:domain', domainAuthorization, async (req, res) => {
* Get full zone as file
*/
api.get('/zone/:domain/download', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const cached = await getOrLoad(domain);
const { cached } = res.locals;
res.send(createZoneFile(cached.zone).join('\n'));
});
@ -406,8 +415,7 @@ api.get('/zone/:domain/download', domainAuthorization, async (req, res) => {
* Get full zone
*/
api.get('/zone/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const cached = await getOrLoad(domain);
const { cached } = res.locals;
res.json(cached.zone);
});
@ -416,8 +424,7 @@ api.get('/zone/:domain', domainAuthorization, async (req, res) => {
* ttl?: number
*/
api.post('/zone/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const cached = await getOrLoad(domain);
const { domain, cached } = res.locals;
if (req.body.ttl) {
const numTTL = parseInt(req.body.TTL, 10);
@ -447,7 +454,7 @@ api.post('/zone/:domain', domainAuthorization, async (req, res) => {
* dualRequest?: boolean;
*/
api.post('/set-ip/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain;
const { domain, cached } = res.locals;
const subdomain = req.body.subdomain || '@';
const waitPartial = req.body.dualRequest === true;
const { v4, v6 } = fromRequest(req);
@ -456,8 +463,7 @@ api.post('/set-ip/:domain', domainAuthorization, async (req, res) => {
res.json({ success: true, message: 'Nothing to do.' });
}
const cached = await getOrLoad(domain);
const { zone } = cached;
const { zone } = cached as CachedZone;
const actions: string[] = [];
if (v4) {
@ -529,7 +535,7 @@ api.post('/set-ip/:domain', domainAuthorization, async (req, res) => {
logger.info('zone %s set-ip from %s: %s', domain, req.ip, actions.join('\n'));
});
const errorHandler: ErrorRequestHandler = (err: any, req: Request, res: Response, next: NextFunction) => {
const errorHandler: ErrorRequestHandler = (err: any, _req: Request, res: Response, _next: NextFunction) => {
res.status(400).json({
success: false,
message: err.message

View File

@ -10,8 +10,8 @@ export class Keys {
let content = '{}';
try {
content = await fs.readFile(file, { encoding: 'utf-8' });
} catch (e) {
if (e.message.includes('ENOENT')) {
} catch (e: unknown) {
if ((e as Error).message.includes('ENOENT')) {
fs.writeFile(file, '{}');
} else {
throw e;