managed endpoint, some error handling changes
This commit is contained in:
parent
6724e8724a
commit
fbadd95c4f
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/node_modules/
|
||||
/keys.json
|
||||
/managed.json
|
||||
*.zone
|
||||
/dist
|
||||
/logs
|
||||
|
1015
package-lock.json
generated
1015
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,14 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/node": "^16.7.10",
|
||||
|
@ -89,9 +89,7 @@ export class DNSCache {
|
||||
await this.validator.validateAndSave(name, zone);
|
||||
} catch (e: any) {
|
||||
// Reload previous state
|
||||
if (e.message.contains('Validation')) {
|
||||
await this.load(name, zone.file);
|
||||
}
|
||||
await this.load(name, zone.file);
|
||||
throw e as Error;
|
||||
}
|
||||
}
|
||||
|
38
src/index.ts
38
src/index.ts
@ -18,6 +18,7 @@ import { fromRequest } from './ip/from-request';
|
||||
import { Keys } from './keys';
|
||||
import { CachedZone } from './models/interfaces';
|
||||
import { logger } from './log/Logger';
|
||||
import { Managed } from './managed';
|
||||
|
||||
const port = parseInt(process.env.PORT || '9129', 10);
|
||||
const cacheTTL = parseInt(process.env.CACHE_TTL || '2629746', 10);
|
||||
@ -35,6 +36,7 @@ app.use(cors({
|
||||
}));
|
||||
|
||||
const keys = new Keys();
|
||||
const managed = new Managed();
|
||||
const rndc = ReloadExecutor.fromEnvironment();
|
||||
const validator = new ValidatorExecutor();
|
||||
const cache = new DNSCache(rndc, validator, cacheTTL);
|
||||
@ -535,6 +537,39 @@ 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 checkManaged: RequestHandler = (req, res, next) => {
|
||||
if (!req.body.name || !req.body.password) {
|
||||
return next(new Error('missing_fields'));
|
||||
}
|
||||
|
||||
// Find user account
|
||||
const findUser = managed.getAccount(req.body.name);
|
||||
if (!findUser) {
|
||||
return next(new Error('invalid'));
|
||||
}
|
||||
console.log(findUser);
|
||||
|
||||
// Validate password
|
||||
managed.validatePassword(findUser, req.body.password).then((success) => {
|
||||
if (success) {
|
||||
res.locals.user = findUser;
|
||||
return next();
|
||||
}
|
||||
|
||||
next(new Error('invalid'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple front-end access utility by username and password
|
||||
*/
|
||||
app.post('/api/v1/managed', checkManaged, (req, res) => {
|
||||
res.json({
|
||||
name: res.locals.user.name,
|
||||
access: res.locals.user.access
|
||||
});
|
||||
});
|
||||
|
||||
const errorHandler: ErrorRequestHandler = (err: any, _req: Request, res: Response, _next: NextFunction) => {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
@ -542,11 +577,12 @@ const errorHandler: ErrorRequestHandler = (err: any, _req: Request, res: Respons
|
||||
});
|
||||
}
|
||||
|
||||
api.use(errorHandler);
|
||||
app.use(errorHandler);
|
||||
app.use('/api/v1', api);
|
||||
|
||||
async function load() {
|
||||
await keys.load();
|
||||
await managed.load();
|
||||
|
||||
if (logger.logToFile) {
|
||||
try {
|
||||
|
32
src/managed.ts
Normal file
32
src/managed.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { compare } from 'bcrypt';
|
||||
import * as fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { User } from './models/managed';
|
||||
|
||||
export class Managed {
|
||||
private accounts: User[] = [];
|
||||
|
||||
async load(): Promise<void> {
|
||||
const file = path.join(__dirname, '..', 'managed.json');
|
||||
let content = '[]';
|
||||
try {
|
||||
content = await fs.readFile(file, { encoding: 'utf-8' });
|
||||
} catch (e: unknown) {
|
||||
if ((e as Error).message.includes('ENOENT')) {
|
||||
fs.writeFile(file, '[]');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
this.accounts = JSON.parse(content);
|
||||
}
|
||||
|
||||
getAccount(name: string): User | undefined {
|
||||
return this.accounts.find((item) => item.name === name);
|
||||
}
|
||||
|
||||
async validatePassword(account: User, password: string): Promise<boolean> {
|
||||
return compare(password, account.password);
|
||||
}
|
||||
}
|
10
src/models/managed.ts
Normal file
10
src/models/managed.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export interface UserAccess {
|
||||
token: string;
|
||||
zone: string;
|
||||
}
|
||||
|
||||
export interface User {
|
||||
name: string;
|
||||
password: string;
|
||||
access: UserAccess[];
|
||||
}
|
Reference in New Issue
Block a user