separate built files, documentation
This commit is contained in:
parent
8caefdbf13
commit
2bd12aeaa3
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
/node_modules/
|
/node_modules/
|
||||||
/keys.json
|
/keys.json
|
||||||
*.zone
|
*.zone
|
||||||
|
/dist
|
||||||
|
20
Dockerfile
Normal file
20
Dockerfile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
RUN apk add --no-cache nodejs npm bind bind-tools
|
||||||
|
WORKDIR /icydns
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install --only production
|
||||||
|
COPY dist/ ./dist/
|
||||||
|
|
||||||
|
RUN mkdir /rndc
|
||||||
|
RUN mkdir /zones
|
||||||
|
|
||||||
|
ENV RNDC_KEYFILE="/rndc/rndc.key"
|
||||||
|
ENV ZONEFILES="/zones"
|
||||||
|
|
||||||
|
VOLUME /zones
|
||||||
|
VOLUME /rndc
|
||||||
|
|
||||||
|
EXPOSE 9129
|
||||||
|
CMD [ "npm", "start" ]
|
176
README.md
Normal file
176
README.md
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
# IcyDNS HTTP API
|
||||||
|
HTTP API for managing BIND zone files.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
This application is intended to be run behind a proxy. Requires node v14+ for `fs/promises`. Also requires `bind-tools` for checking zone files.
|
||||||
|
|
||||||
|
* `npm install`
|
||||||
|
* `npm run build`
|
||||||
|
* `npm start`
|
||||||
|
|
||||||
|
### Environment variables
|
||||||
|
* `PORT` - server port
|
||||||
|
* `ZONEFILES` - path to zone files
|
||||||
|
* `CACHE_TTL` - internal zone cache time-to-live
|
||||||
|
* `RNDC_SERVER` - RNDC host
|
||||||
|
* `RNDC_PORT` - RNDC port
|
||||||
|
* `RNDC_KEYFILE` - location of RNDC's key file
|
||||||
|
|
||||||
|
Zones are automatically reloaded using `rndc` after updates. If you do not have rndc configured, you will need to reload the zones manually, but the files still get updated.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
**All requests are prefixed with `/api/v1`.** Authorization is by bearer token, i.e. `-H 'Authorization: Bearer <token>'`. `?` denotes optional parameter.
|
||||||
|
|
||||||
|
### `GET /zone/:domain`
|
||||||
|
Returns all of `:domain`'s DNS records.
|
||||||
|
|
||||||
|
**Query:** None
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
ttl: number;
|
||||||
|
records: [
|
||||||
|
[index]: {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `GET /zone/:domain/download`
|
||||||
|
Provides `:domain`'s records as a file.
|
||||||
|
|
||||||
|
**Query:** None
|
||||||
|
|
||||||
|
**Response:** BIND zone file
|
||||||
|
|
||||||
|
### `POST /zone/:domain`
|
||||||
|
Reloads `:domain`'s zone file. Optionally changes the zone file's TTL value.
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
ttl?: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
ttl?: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `GET /zone/records/:domain`
|
||||||
|
Returns all of `:domain`'s DNS records or performs a search based on provided query parameters.
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
* `name?`
|
||||||
|
* `type?`
|
||||||
|
* `value?`
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```typescript
|
||||||
|
[
|
||||||
|
[index]: {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
index?: number; // when searching only
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### `POST /zone/records/:domain`
|
||||||
|
Updates a DNS record of `:domain` at `index`.
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
index: number;
|
||||||
|
record: {
|
||||||
|
name?: string;
|
||||||
|
type?: string;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
record: DNSRecord;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `PUT /zone/records/:domain`
|
||||||
|
Creates a new DNS record for `:domain`.
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
record: {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
record: DNSRecord;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `DELETE /zone/records/:domain`
|
||||||
|
Deletes a DNS record from `:domain` at `index`.
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
index: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
record: DNSRecord;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `POST /set-ip/:domain`
|
||||||
|
Quickly updates the `:domain`'s IP address (first occurences of `A` and `AAAA` records of `@` or `subdomain`). One of the IP addresses is taken from the request, so it's a good idea to use curl with `-4` to automatically set the IPv4 address and provide the IPv6 address with a body parameter.
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
ipv4?: string;
|
||||||
|
ipv6?: string;
|
||||||
|
subdomain?: string;
|
||||||
|
dualRequest?: boolean;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
actions: string[]; // detailed descriptions of what was actually done
|
||||||
|
}
|
||||||
|
```
|
@ -7,7 +7,7 @@
|
|||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"watch": "tsc -w",
|
"watch": "tsc -w",
|
||||||
"start": "node src/index.js"
|
"start": "node dist/index.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
@ -84,7 +84,15 @@ export class DNSCache {
|
|||||||
throw new Error('No such cached zone file!');
|
throw new Error('No such cached zone file!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
await this.validator.validateAndSave(name, zone);
|
await this.validator.validateAndSave(name, zone);
|
||||||
|
} catch (e) {
|
||||||
|
// Reload previous state
|
||||||
|
if (e.message.contains('Validation')) {
|
||||||
|
await this.load(name, zone.file);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(name: string, newZone?: CachedZone, skipReload = false): Promise<void> {
|
async update(name: string, newZone?: CachedZone, skipReload = false): Promise<void> {
|
||||||
|
@ -37,7 +37,7 @@ function parseRecordLine(line: string, index: number, lines: string[]): DNSRecor
|
|||||||
if (split[2] === 'SOA') {
|
if (split[2] === 'SOA') {
|
||||||
return {
|
return {
|
||||||
name: split[0],
|
name: split[0],
|
||||||
type: DNSRecordType[split[2]],
|
type: DNSRecordType.SOA,
|
||||||
value: split.slice(3).join(' '),
|
value: split.slice(3).join(' '),
|
||||||
nameserver: split[3],
|
nameserver: split[3],
|
||||||
email: split[4],
|
email: split[4],
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
"outDir": "./dist", /* Redirect output structure to the directory. */
|
||||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
// "composite": true, /* Enable project compilation */
|
// "composite": true, /* Enable project compilation */
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
|
Reference in New Issue
Block a user