delete multiple records at once

This commit is contained in:
Evert Prants 2021-05-16 17:40:48 +03:00
parent 176a3f66b0
commit cc2f4fea84
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
4 changed files with 63 additions and 15 deletions

View File

@ -88,7 +88,7 @@ Returns all of `:domain`'s DNS records or performs a search based on provided qu
``` ```
### `POST /zone/records/:domain` ### `POST /zone/records/:domain`
Updates a single or multiple DNS records of `:domain` at `index`. Updates or marks for deletion a single or multiple DNS records of `:domain` at `index`.
**Body:** **Body:**
```typescript ```typescript
@ -98,6 +98,7 @@ Updates a single or multiple DNS records of `:domain` at `index`.
name?: string; name?: string;
type?: string; type?: string;
value?: string; value?: string;
forDeletion?: boolean;
} | {...}[]; } | {...}[];
} }
``` ```
@ -143,12 +144,12 @@ Creates a single or multiple new DNS records for `:domain`.
``` ```
### `DELETE /zone/records/:domain` ### `DELETE /zone/records/:domain`
Deletes a DNS record from `:domain` at `index`. **Warning:** Deleting an index that is not at the end of the record causes following records' indexes to shift back by one. Deletes a single or multiple DNS records from `:domain` at `index`. **Warning:** Deleting an index that is not at the end of the record causes following records' indexes to shift back by one. Refresh your indexes after every addition and deletion!
**Body:** **Body:**
```typescript ```typescript
{ {
index: number; index: number | number[];
} }
``` ```
@ -157,7 +158,11 @@ Deletes a DNS record from `:domain` at `index`. **Warning:** Deleting an index t
{ {
success: boolean; success: boolean;
message: string; message: string;
record: DNSRecord; deleted: DNSRecord[];
errors: {
message: string;
record: DNSRecord;
}[];
} }
``` ```

View File

@ -107,9 +107,13 @@ export class DNSCache {
throw new Error('No such cached zone file!'); throw new Error('No such cached zone file!');
} }
zone.changed = new Date(); // Delete marked-for-deletion records
zone.zone.records = zone.zone.records.filter((record) => record.forDeletion !== true);
// Set new serial
const soa = zone.zone.records.find((record) => record.type === DNSRecordType.SOA) as SOARecord; const soa = zone.zone.records.find((record) => record.type === DNSRecordType.SOA) as SOARecord;
soa.serial = Math.floor(Date.now() / 1000); soa.serial = Math.floor(Date.now() / 1000);
zone.changed = new Date();
this.set(name, zone); this.set(name, zone);
await this.save(name); await this.save(name);

View File

@ -107,6 +107,7 @@ api.get('/zone/records/:domain', domainAuthorization, async (req, res) => {
* name?: string; * name?: string;
* type?: DNSRecordType; * type?: DNSRecordType;
* value?: string; * value?: string;
* forDeletion?: boolean;
* }[]; * }[];
*/ */
api.post('/zone/records/:domain', domainAuthorization, async (req, res) => { api.post('/zone/records/:domain', domainAuthorization, async (req, res) => {
@ -166,8 +167,18 @@ api.post('/zone/records/:domain', domainAuthorization, async (req, res) => {
} }
} }
if (record.type === DNSRecordType.SOA && setter.forDeletion) {
errors.push({
message: 'Cannot delete the Start Of Authority record.',
record
});
continue;
}
keys.forEach((key) => { keys.forEach((key) => {
if (record[key]) { if (key === 'forDeletion') {
record.forDeletion = true;
} else if (record[key]) {
record[key] = setter[key]; record[key] = setter[key];
} }
}); });
@ -201,23 +212,50 @@ api.post('/zone/records/:domain', domainAuthorization, async (req, res) => {
*/ */
api.delete('/zone/records/:domain', domainAuthorization, async (req, res) => { api.delete('/zone/records/:domain', domainAuthorization, async (req, res) => {
const domain = req.params.domain; const domain = req.params.domain;
const index = parseInt(req.body.index, 10); let indexes = req.body.index;
const cached = await getOrLoad(domain); const cached = await getOrLoad(domain);
const { zone } = cached; const { zone } = cached;
if (!index || isNaN(index) || !zone.records[index]) {
throw new Error('Invalid record index.'); if (!Array.isArray(indexes)) {
indexes = [indexes];
} }
const record = zone.records[index]; const deleted = [];
if (record.type === DNSRecordType.SOA) { const errors = [];
throw new Error('Cannot delete the Start Of Authority record.');
for (const number of indexes) {
const index = parseInt(number, 10);
if (index == null || isNaN(index) || !zone.records[index]) {
errors.push({
message: 'Invalid record index.',
record: { index }
});
continue;
}
const record = zone.records[index];
if (record.type === DNSRecordType.SOA) {
errors.push({
message: 'Cannot delete the Start Of Authority record.',
record
});
continue;
}
zone.records[index].forDeletion = true;
deleted.push(record);
} }
zone.records.splice(index, 1);
await cache.update(domain, cached); await cache.update(domain, cached);
res.json({ success: true, message: 'Record deleted successfully.', record }); if (!deleted.length && errors.length) {
res.status(400).json({ success: false, message: 'Deleting record(s) failed.', deleted, errors });
} else if (deleted.length) {
res.json({ success: true, message: 'Record(s) deleted successfully.', deleted, errors });
} else {
res.json({ success: true, message: 'Nothing was deleted.', deleted, errors });
}
}); });
/** /**

View File

@ -1,10 +1,11 @@
import { DNSRecordType } from "../dns/records"; import { DNSRecordType } from "../dns/records";
export interface DNSRecord { export interface DNSRecord {
[key: string]: string | number; [key: string]: string | number | boolean | undefined;
name: string; name: string;
type: DNSRecordType; type: DNSRecordType;
value: string; value: string;
forDeletion?: boolean;
} }
export interface SOARecord extends DNSRecord { export interface SOARecord extends DNSRecord {