Compare commits
No commits in common. "master" and "1.0.0" have entirely different histories.
30 changed files with 171 additions and 629 deletions
26
.github/workflows/build.yml
vendored
26
.github/workflows/build.yml
vendored
|
@ -1,26 +0,0 @@
|
|||
---
|
||||
name: 'build go project'
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd dyndns
|
||||
go build -v ./...
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd dyndns
|
||||
go test -v ./...
|
54
.github/workflows/containers.yml
vendored
54
.github/workflows/containers.yml
vendored
|
@ -1,54 +0,0 @@
|
|||
---
|
||||
name: 'build images'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Prepare
|
||||
id: prep
|
||||
run: |
|
||||
DOCKER_IMAGE=${{ secrets.DOCKER_USERNAME }}/${GITHUB_REPOSITORY#*/}
|
||||
VERSION=${GITHUB_REF/refs\/tags\//}
|
||||
SHORTREF=${GITHUB_SHA::8}
|
||||
TAGS="${DOCKER_IMAGE}:${VERSION},${DOCKER_IMAGE}:latest"
|
||||
|
||||
# Set output parameters
|
||||
echo ::set-output name=version::${VERSION}
|
||||
echo ::set-output name=tags::${TAGS}
|
||||
echo ::set-output name=docker_image::${DOCKER_IMAGE}
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
run: echo ::set-output name=version::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@master
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@master
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
file: ./deployment/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64,linux/arm
|
||||
push: true
|
||||
tags: ${{ steps.prep.outputs.tags }}
|
22
.travis.yml
Normal file
22
.travis.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
language: go
|
||||
|
||||
env: GO111MODULE=on
|
||||
|
||||
go:
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
before_script:
|
||||
- cd dyndns
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
||||
- go build ./...
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: always
|
13
README.md
13
README.md
|
@ -1,12 +1,14 @@
|
|||
# Dynamic DNS Server for Docker with Web UI written in Go
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
With docker-ddns-server you can set up your own dynamic DNS server. This project is inspired by https://github.com/dprandzioch/docker-ddns . In addition to the original version, you can setup and maintain your dyndns entries via simple web ui.
|
||||
With docker-ddns-server you can setup your own dynamic DNS server. This project is inspired by https://github.com/dprandzioch/docker-ddns . In addition to the original version, you can setup and maintain your dyndns entries via simple web ui.
|
||||
|
||||
<p float="left">
|
||||
<img src="https://raw.githubusercontent.com/benjaminbear/docker-ddns-server/master/img/addhost.png" width="285">
|
||||
|
@ -28,7 +30,7 @@ docker run -it -d \
|
|||
-p 53:53 \
|
||||
-p 53:53/udp \
|
||||
-v /somefolder:/var/cache/bind \
|
||||
-v /someotherfolder:/root/database \
|
||||
-v /someotherfolder:/root/dyndns/database \
|
||||
-e DDNS_ADMIN_LOGIN=admin:123455546. \
|
||||
-e DDNS_DOMAINS=dyndns.example.com \
|
||||
-e DDNS_PARENT_NS=ns.example.com \
|
||||
|
@ -51,7 +53,6 @@ If you want to embed this into a docker-compose.yml you have to double the dolla
|
|||
```
|
||||
echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
|
||||
```
|
||||
If `DDNS_ADMIN_LOGIN` is not set, all /admin routes are without protection. (use case: auth proxy)
|
||||
|
||||
`DDNS_DOMAINS` are the domains of the webservice and the domain zones of your dyndns server (see DNS Setup) i.e. `dyndns.example.com,dyndns.example.org` (comma separated list)
|
||||
|
||||
|
@ -59,12 +60,6 @@ If `DDNS_ADMIN_LOGIN` is not set, all /admin routes are without protection. (use
|
|||
|
||||
`DDNS_DEFAULT_TTL` is the default TTL of your dyndns server.
|
||||
|
||||
`DDNS_CLEAR_LOG_INTERVAL` optional: clear log entries automatically in days (integer) e.g. `DDNS_CLEAR_LOG_INTERVAL:30`
|
||||
|
||||
`DDNS_ALLOW_WILDCARD` optional: allows all `*.subdomain.dyndns.example.com` to point to your ip (boolean) e.g. `true`
|
||||
|
||||
`DDNS_LOGOUT_URL` optional: allows a logout redirect to certain url by clicking the logout button (string) e.g. `https://example.com`
|
||||
|
||||
### DNS setup
|
||||
|
||||
If your parent domain is `example.com` and you want your dyndns domain to be `dyndns.example.com`,
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
FROM golang:1.20 as builder
|
||||
FROM golang:latest as builder
|
||||
|
||||
ENV GO111MODULE=on
|
||||
ENV GOPATH=/root/go
|
||||
RUN mkdir -p /root/go/src
|
||||
COPY dyndns /root/go/src/dyndns
|
||||
WORKDIR /root/go/src/dyndns
|
||||
# temp sqlite3 error fix
|
||||
ENV CGO_CFLAGS "-g -O2 -Wno-return-local-addr"
|
||||
RUN go mod tidy
|
||||
RUN GOOS=linux go build -o /root/go/bin/dyndns && go test -v
|
||||
RUN cd /root/go/src/dyndns && go mod download && GOOS=linux GOARCH=amd64 go build -o /root/go/bin/dyndns && go test -v
|
||||
|
||||
FROM debian:11-slim
|
||||
FROM debian:buster-slim
|
||||
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||
apt-get install -q -y bind9 dnsutils curl && \
|
||||
|
@ -27,4 +23,4 @@ COPY dyndns/views /root/views
|
|||
COPY dyndns/static /root/static
|
||||
|
||||
EXPOSE 53 8080
|
||||
CMD ["sh", "-c", "/root/setup.sh ; service named start ; /root/dyndns"]
|
||||
CMD ["sh", "-c", "/root/setup.sh ; service bind9 start ; /root/dyndns"]
|
||||
|
|
|
@ -14,4 +14,4 @@ services:
|
|||
- "8080:8080"
|
||||
volumes:
|
||||
- ./bind-data:/var/cache/bind
|
||||
- ./database:/root/database
|
||||
- ./database:/root/dyndns/database
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
#[ -z "$DDNS_ADMIN_LOGIN" ] && echo "DDNS_ADMIN_LOGIN not set" && exit 1;
|
||||
[ -z "$DDNS_ADMIN_LOGIN" ] && echo "DDNS_ADMIN_LOGIN not set" && exit 1;
|
||||
[ -z "$DDNS_DOMAINS" ] && echo "DDNS_DOMAINS not set" && exit 1;
|
||||
[ -z "$DDNS_PARENT_NS" ] && echo "DDNS_PARENT_NS not set" && exit 1;
|
||||
[ -z "$DDNS_DEFAULT_TTL" ] && echo "DDNS_DEFAULT_TTL not set" && exit 1;
|
||||
|
@ -48,4 +48,4 @@ done
|
|||
chown root:bind /var/cache/bind
|
||||
chown bind:bind /var/cache/bind/*
|
||||
chmod 770 /var/cache/bind
|
||||
chmod 644 /var/cache/bind/*
|
||||
chmod 644 /var/cache/bind/*
|
|
@ -1,32 +1,12 @@
|
|||
module github.com/benjaminbear/docker-ddns-server/dyndns
|
||||
|
||||
go 1.20
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/foolin/goview v0.3.0
|
||||
github.com/go-playground/validator/v10 v10.14.0
|
||||
github.com/go-playground/validator/v10 v10.8.0
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/labstack/echo/v4 v4.10.2
|
||||
github.com/labstack/gommon v0.4.0
|
||||
github.com/tg123/go-htpasswd v1.2.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
github.com/labstack/echo/v4 v4.4.0
|
||||
github.com/labstack/gommon v0.3.0
|
||||
github.com/tg123/go-htpasswd v1.0.0
|
||||
)
|
||||
|
|
135
dyndns/go.sum
135
dyndns/go.sum
|
@ -1,135 +0,0 @@
|
|||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw=
|
||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/foolin/goview v0.3.0 h1:q5wKwXKEFb20dMRfYd59uj5qGCo7q4L9eVHHUjmMWrg=
|
||||
github.com/foolin/goview v0.3.0/go.mod h1:OC1VHC4FfpWymhShj8L1Tc3qipFmrmm+luAEdTvkos4=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/echo/v4 v4.1.6/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
|
||||
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
|
||||
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
||||
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
|
||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tg123/go-htpasswd v1.2.1 h1:i4wfsX1KvvkyoMiHZzjS0VzbAPWfxzI8INcZAKtutoU=
|
||||
github.com/tg123/go-htpasswd v1.2.1/go.mod h1:erHp1B86KXdwQf1X5ZrLb7erXZnWueEQezb2dql4q58=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190609082536-301114b31cce/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -24,7 +24,6 @@ func (h *Handler) ListCNames(c echo.Context) (err error) {
|
|||
|
||||
return c.Render(http.StatusOK, "listcnames", echo.Map{
|
||||
"cnames": cnames,
|
||||
"title": h.Title,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -43,7 +42,6 @@ func (h *Handler) AddCName(c echo.Context) (err error) {
|
|||
return c.Render(http.StatusOK, "addcname", echo.Map{
|
||||
"config": h.Config,
|
||||
"hosts": hosts,
|
||||
"title": h.Title,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -79,7 +77,7 @@ func (h *Handler) CreateCName(c echo.Context) (err error) {
|
|||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
if err = nswrapper.UpdateRecord(cname.Hostname, fmt.Sprintf("%s.%s", cname.Target.Hostname, cname.Target.Domain), "CNAME", cname.Target.Domain, cname.Ttl, h.AllowWildcard); err != nil {
|
||||
if err = nswrapper.UpdateRecord(cname.Hostname, fmt.Sprintf("%s.%s", cname.Target.Hostname, cname.Target.Domain), "CNAME", cname.Target.Domain, cname.Ttl); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
|
@ -114,7 +112,7 @@ func (h *Handler) DeleteCName(c echo.Context) (err error) {
|
|||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
if err = nswrapper.DeleteRecord(cname.Hostname, cname.Target.Domain, h.AllowWildcard); err != nil {
|
||||
if err = nswrapper.DeleteRecord(cname.Hostname, cname.Target.Domain); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,8 @@ package handler
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/labstack/gommon/log"
|
||||
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/benjaminbear/docker-ddns-server/dyndns/model"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
@ -17,15 +13,10 @@ import (
|
|||
)
|
||||
|
||||
type Handler struct {
|
||||
DB *gorm.DB
|
||||
AuthAdmin bool
|
||||
Config Envs
|
||||
Title string
|
||||
DisableAdminAuth bool
|
||||
LastClearedLogs time.Time
|
||||
ClearInterval uint64
|
||||
AllowWildcard bool
|
||||
LogoutUrl string
|
||||
DB *gorm.DB
|
||||
AuthHost *model.Host
|
||||
AuthAdmin bool
|
||||
Config Envs
|
||||
}
|
||||
|
||||
type Envs struct {
|
||||
|
@ -48,33 +39,13 @@ type Error struct {
|
|||
|
||||
// Authenticate is the method the website admin user and the host update user have to authenticate against.
|
||||
// To gather admin rights the username password combination must match with the credentials given by the env var.
|
||||
func (h *Handler) AuthenticateUpdate(username, password string, c echo.Context) (bool, error) {
|
||||
h.CheckClearInterval()
|
||||
reqParameter := c.QueryParam("hostname")
|
||||
reqArr := strings.SplitN(reqParameter, ".", 2)
|
||||
if len(reqArr) != 2 {
|
||||
log.Error("Error: Something wrong with the hostname parameter")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
host := &model.Host{}
|
||||
if err := h.DB.Where(&model.Host{UserName: username, Password: password, Hostname: reqArr[0], Domain: reqArr[1]}).First(host).Error; err != nil {
|
||||
log.Error("Error: ", err)
|
||||
return false, nil
|
||||
}
|
||||
if host.ID == 0 {
|
||||
log.Error("hostname or user user credentials unknown")
|
||||
return false, nil
|
||||
}
|
||||
c.Set("updateHost", host)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
func (h *Handler) AuthenticateAdmin(username, password string, c echo.Context) (bool, error) {
|
||||
func (h *Handler) Authenticate(username, password string, c echo.Context) (bool, error) {
|
||||
h.AuthHost = nil
|
||||
h.AuthAdmin = false
|
||||
|
||||
ok, err := h.authByEnv(username, password)
|
||||
if err != nil {
|
||||
log.Error("Error:", err)
|
||||
fmt.Println("Error:", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
@ -83,8 +54,17 @@ func (h *Handler) AuthenticateAdmin(username, password string, c echo.Context) (
|
|||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
host := &model.Host{}
|
||||
if err := h.DB.Where(&model.Host{UserName: username, Password: password}).First(host).Error; err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
h.AuthHost = host
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (h *Handler) authByEnv(username, password string) (bool, error) {
|
||||
hashReader := strings.NewReader(h.Config.AdminLogin)
|
||||
|
||||
|
@ -103,55 +83,19 @@ func (h *Handler) authByEnv(username, password string) (bool, error) {
|
|||
// ParseEnvs parses all needed environment variables:
|
||||
// DDNS_ADMIN_LOGIN: The basic auth login string in htpasswd style.
|
||||
// DDNS_DOMAINS: All domains that will be handled by the dyndns server.
|
||||
func (h *Handler) ParseEnvs() (adminAuth bool, err error) {
|
||||
log.Info("Read environment variables")
|
||||
func (h *Handler) ParseEnvs() error {
|
||||
h.Config = Envs{}
|
||||
adminAuth = true
|
||||
h.Config.AdminLogin = os.Getenv("DDNS_ADMIN_LOGIN")
|
||||
if h.Config.AdminLogin == "" {
|
||||
log.Info("No Auth! DDNS_ADMIN_LOGIN should be set")
|
||||
adminAuth = false
|
||||
h.AuthAdmin = true
|
||||
h.DisableAdminAuth = true
|
||||
}
|
||||
var ok bool
|
||||
h.Title, ok = os.LookupEnv("DDNS_TITLE")
|
||||
if !ok {
|
||||
h.Title = "TheBBCloud DynDNS"
|
||||
}
|
||||
allowWildcard, ok := os.LookupEnv("DDNS_ALLOW_WILDCARD")
|
||||
if ok {
|
||||
h.AllowWildcard, err = strconv.ParseBool(allowWildcard)
|
||||
if err == nil {
|
||||
log.Info("Wildcard allowed")
|
||||
}
|
||||
}
|
||||
logoutUrl, ok := os.LookupEnv("DDNS_LOGOUT_URL")
|
||||
if ok {
|
||||
if len(logoutUrl) > 0 {
|
||||
log.Info("Logout url set: ", logoutUrl)
|
||||
h.LogoutUrl = logoutUrl
|
||||
}
|
||||
}
|
||||
|
||||
clearEnv := os.Getenv("DDNS_CLEAR_LOG_INTERVAL")
|
||||
clearInterval, err := strconv.ParseUint(clearEnv, 10, 32)
|
||||
if err != nil {
|
||||
log.Info("No log clear interval found")
|
||||
} else {
|
||||
log.Info("log clear interval found: ", clearInterval, "days")
|
||||
h.ClearInterval = clearInterval
|
||||
if clearInterval > 0 {
|
||||
h.LastClearedLogs = time.Now()
|
||||
}
|
||||
return fmt.Errorf("environment variable DDNS_ADMIN_LOGIN has to be set")
|
||||
}
|
||||
|
||||
h.Config.Domains = strings.Split(os.Getenv("DDNS_DOMAINS"), ",")
|
||||
if len(h.Config.Domains) < 1 {
|
||||
return adminAuth, fmt.Errorf("environment variable DDNS_DOMAINS has to be set")
|
||||
return fmt.Errorf("environment variable DDNS_DOMAINS has to be set")
|
||||
}
|
||||
|
||||
return adminAuth, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitDB creates an empty database and creates all tables if there isn't already one, or opens the existing one.
|
||||
|
@ -182,19 +126,3 @@ func (h *Handler) InitDB() (err error) {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if a log cleaning is needed
|
||||
func (h *Handler) CheckClearInterval() {
|
||||
if !h.LastClearedLogs.IsZero() {
|
||||
if !DateEqual(time.Now(), h.LastClearedLogs) {
|
||||
go h.ClearLogs()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compare two dates
|
||||
func DateEqual(date1, date2 time.Time) bool {
|
||||
y1, m1, d1 := date1.Date()
|
||||
y2, m2, d2 := date2.Date()
|
||||
return y1 == y2 && m1 == m2 && d1 == d2
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package handler
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
l "github.com/labstack/gommon/log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
@ -52,7 +51,6 @@ func (h *Handler) ListHosts(c echo.Context) (err error) {
|
|||
|
||||
return c.Render(http.StatusOK, "listhosts", echo.Map{
|
||||
"hosts": hosts,
|
||||
"title": h.Title,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -65,7 +63,6 @@ func (h *Handler) AddHost(c echo.Context) (err error) {
|
|||
return c.Render(http.StatusOK, "edithost", echo.Map{
|
||||
"addEdit": "add",
|
||||
"config": h.Config,
|
||||
"title": h.Title,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -89,7 +86,6 @@ func (h *Handler) EditHost(c echo.Context) (err error) {
|
|||
"host": host,
|
||||
"addEdit": "edit",
|
||||
"config": h.Config,
|
||||
"title": h.Title,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -113,7 +109,7 @@ func (h *Handler) CreateHost(c echo.Context) (err error) {
|
|||
if err = h.checkUniqueHostname(host.Hostname, host.Domain); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
host.LastUpdate = time.Now()
|
||||
|
||||
if err = h.DB.Create(host).Error; err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
@ -125,7 +121,7 @@ func (h *Handler) CreateHost(c echo.Context) (err error) {
|
|||
return c.JSON(http.StatusBadRequest, &Error{fmt.Sprintf("ip %s is not a valid ip", host.Ip)})
|
||||
}
|
||||
|
||||
if err = nswrapper.UpdateRecord(host.Hostname, host.Ip, ipType, host.Domain, host.Ttl, h.AllowWildcard); err != nil {
|
||||
if err = nswrapper.UpdateRecord(host.Hostname, host.Ip, ipType, host.Domain, host.Ttl); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +168,7 @@ func (h *Handler) UpdateHost(c echo.Context) (err error) {
|
|||
return c.JSON(http.StatusBadRequest, &Error{fmt.Sprintf("ip %s is not a valid ip", host.Ip)})
|
||||
}
|
||||
|
||||
if err = nswrapper.UpdateRecord(host.Hostname, host.Ip, ipType, host.Domain, host.Ttl, h.AllowWildcard); err != nil {
|
||||
if err = nswrapper.UpdateRecord(host.Hostname, host.Ip, ipType, host.Domain, host.Ttl); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +212,7 @@ func (h *Handler) DeleteHost(c echo.Context) (err error) {
|
|||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
if err = nswrapper.DeleteRecord(host.Hostname, host.Domain, h.AllowWildcard); err != nil {
|
||||
if err = nswrapper.DeleteRecord(host.Hostname, host.Domain); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
|
@ -227,12 +223,11 @@ func (h *Handler) DeleteHost(c echo.Context) (err error) {
|
|||
// Hostname, IP and senders IP are validated, a log entry is created
|
||||
// and finally if everything is ok, the DNS Server will be updated
|
||||
func (h *Handler) UpdateIP(c echo.Context) (err error) {
|
||||
host, ok := c.Get("updateHost").(*model.Host)
|
||||
if !ok {
|
||||
if h.AuthHost == nil {
|
||||
return c.String(http.StatusBadRequest, "badauth\n")
|
||||
}
|
||||
|
||||
log := &model.Log{Status: false, Host: *host, TimeStamp: time.Now(), UserAgent: nswrapper.ShrinkUserAgent(c.Request().UserAgent())}
|
||||
log := &model.Log{Status: false, Host: *h.AuthHost, TimeStamp: time.Now(), UserAgent: nswrapper.ShrinkUserAgent(c.Request().UserAgent())}
|
||||
log.SentIP = c.QueryParam(("myip"))
|
||||
|
||||
// Get caller IP
|
||||
|
@ -242,7 +237,7 @@ func (h *Handler) UpdateIP(c echo.Context) (err error) {
|
|||
if err != nil {
|
||||
log.Message = "Bad Request: Unable to get caller IP"
|
||||
if err = h.CreateLogEntry(log); err != nil {
|
||||
l.Error(err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
return c.String(http.StatusBadRequest, "badrequest\n")
|
||||
|
@ -251,10 +246,10 @@ func (h *Handler) UpdateIP(c echo.Context) (err error) {
|
|||
|
||||
// Validate hostname
|
||||
hostname := c.QueryParam("hostname")
|
||||
if hostname == "" || hostname != host.Hostname+"."+host.Domain {
|
||||
if hostname == "" || hostname != h.AuthHost.Hostname+"."+h.AuthHost.Domain {
|
||||
log.Message = "Hostname or combination of authenticated user and hostname is invalid"
|
||||
if err = h.CreateLogEntry(log); err != nil {
|
||||
l.Error(err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
return c.String(http.StatusBadRequest, "notfqdn\n")
|
||||
|
@ -268,7 +263,7 @@ func (h *Handler) UpdateIP(c echo.Context) (err error) {
|
|||
if ipType == "" {
|
||||
log.Message = "Bad Request: Sent IP is invalid"
|
||||
if err = h.CreateLogEntry(log); err != nil {
|
||||
l.Error(err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
return c.String(http.StatusBadRequest, "badrequest\n")
|
||||
|
@ -276,12 +271,12 @@ func (h *Handler) UpdateIP(c echo.Context) (err error) {
|
|||
}
|
||||
|
||||
// add/update DNS record
|
||||
if err = nswrapper.UpdateRecord(log.Host.Hostname, log.SentIP, ipType, log.Host.Domain, log.Host.Ttl, h.AllowWildcard); err != nil {
|
||||
if err = nswrapper.UpdateRecord(log.Host.Hostname, log.SentIP, ipType, log.Host.Domain, log.Host.Ttl); err != nil {
|
||||
log.Message = fmt.Sprintf("DNS error: %v", err)
|
||||
l.Error(log.Message)
|
||||
if err = h.CreateLogEntry(log); err != nil {
|
||||
l.Error(err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
return c.String(http.StatusBadRequest, "dnserr\n")
|
||||
}
|
||||
|
||||
|
@ -290,7 +285,7 @@ func (h *Handler) UpdateIP(c echo.Context) (err error) {
|
|||
log.Status = true
|
||||
log.Message = "No errors occurred"
|
||||
if err = h.CreateLogEntry(log); err != nil {
|
||||
l.Error(err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
return c.String(http.StatusOK, "good\n")
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/benjaminbear/docker-ddns-server/dyndns/model"
|
||||
"github.com/labstack/echo/v4"
|
||||
|
@ -26,13 +24,12 @@ func (h *Handler) ShowLogs(c echo.Context) (err error) {
|
|||
}
|
||||
|
||||
logs := new([]model.Log)
|
||||
if err = h.DB.Preload("Host").Limit(30).Order("created_at desc").Find(logs).Error; err != nil {
|
||||
if err = h.DB.Preload("Host").Limit(30).Find(logs).Error; err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "listlogs", echo.Map{
|
||||
"logs": logs,
|
||||
"title": h.Title,
|
||||
"logs": logs,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -48,19 +45,11 @@ func (h *Handler) ShowHostLogs(c echo.Context) (err error) {
|
|||
}
|
||||
|
||||
logs := new([]model.Log)
|
||||
if err = h.DB.Preload("Host").Where(&model.Log{HostID: uint(id)}).Order("created_at desc").Limit(30).Find(logs).Error; err != nil {
|
||||
if err = h.DB.Preload("Host").Where(&model.Log{HostID: uint(id)}).Limit(30).Find(logs).Error; err != nil {
|
||||
return c.JSON(http.StatusBadRequest, &Error{err.Error()})
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "listlogs", echo.Map{
|
||||
"logs": logs,
|
||||
"title": h.Title,
|
||||
"logs": logs,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) ClearLogs() {
|
||||
var clearInterval = strconv.FormatUint(h.ClearInterval, 10) + " day"
|
||||
h.DB.Exec("DELETE FROM LOGS WHERE created_at < datetime('now', '-" + clearInterval + "');REINDEX LOGS;")
|
||||
h.LastClearedLogs = time.Now()
|
||||
log.Print("logs cleared")
|
||||
}
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/benjaminbear/docker-ddns-server/dyndns/handler"
|
||||
"github.com/foolin/goview"
|
||||
"github.com/foolin/goview/supports/echoview-v4"
|
||||
"github.com/go-playground/validator/v10"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"github.com/labstack/gommon/log"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Set new instance
|
||||
e := echo.New()
|
||||
|
||||
e.Logger.SetLevel(log.ERROR)
|
||||
|
@ -23,17 +20,7 @@ func main() {
|
|||
e.Use(middleware.Logger())
|
||||
|
||||
// Set Renderer
|
||||
e.Renderer = echoview.New(goview.Config{
|
||||
Root: "views",
|
||||
Master: "layouts/master",
|
||||
Extension: ".html",
|
||||
Funcs: template.FuncMap{
|
||||
"year": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
e.Renderer = echoview.Default()
|
||||
|
||||
// Set Validator
|
||||
e.Validator = &handler.CustomValidator{Validator: validator.New()}
|
||||
|
@ -50,69 +37,38 @@ func main() {
|
|||
}
|
||||
defer h.DB.Close()
|
||||
|
||||
authAdmin, err := h.ParseEnvs()
|
||||
if err != nil {
|
||||
if err := h.ParseEnvs(); err != nil {
|
||||
e.Logger.Fatal(err)
|
||||
}
|
||||
|
||||
// UI Routes
|
||||
groupPublic := e.Group("/")
|
||||
groupPublic.GET("*", func(c echo.Context) error {
|
||||
//redirect to admin
|
||||
return c.Redirect(301, "./admin/")
|
||||
})
|
||||
groupAdmin := e.Group("/admin")
|
||||
if authAdmin {
|
||||
groupAdmin.Use(middleware.BasicAuth(h.AuthenticateAdmin))
|
||||
}
|
||||
e.Use(middleware.BasicAuth(h.Authenticate))
|
||||
|
||||
groupAdmin.GET("/", h.ListHosts)
|
||||
groupAdmin.GET("/hosts/add", h.AddHost)
|
||||
groupAdmin.GET("/hosts/edit/:id", h.EditHost)
|
||||
groupAdmin.GET("/hosts", h.ListHosts)
|
||||
groupAdmin.GET("/cnames/add", h.AddCName)
|
||||
groupAdmin.GET("/cnames", h.ListCNames)
|
||||
groupAdmin.GET("/logs", h.ShowLogs)
|
||||
groupAdmin.GET("/logs/host/:id", h.ShowHostLogs)
|
||||
// UI Routes
|
||||
e.GET("/", func(c echo.Context) error {
|
||||
//render with master
|
||||
return c.Render(http.StatusOK, "listhosts", nil)
|
||||
})
|
||||
|
||||
e.GET("/hosts/add", h.AddHost)
|
||||
e.GET("/hosts/edit/:id", h.EditHost)
|
||||
e.GET("/hosts", h.ListHosts)
|
||||
e.GET("/cnames/add", h.AddCName)
|
||||
e.GET("/cnames", h.ListCNames)
|
||||
e.GET("/logs", h.ShowLogs)
|
||||
e.GET("/logs/host/:id", h.ShowHostLogs)
|
||||
|
||||
// Rest Routes
|
||||
groupAdmin.POST("/hosts/add", h.CreateHost)
|
||||
groupAdmin.POST("/hosts/edit/:id", h.UpdateHost)
|
||||
groupAdmin.GET("/hosts/delete/:id", h.DeleteHost)
|
||||
//redirect to logout
|
||||
groupAdmin.GET("/logout", func(c echo.Context) error {
|
||||
// either custom url
|
||||
if len(h.LogoutUrl) > 0 {
|
||||
return c.Redirect(302, h.LogoutUrl)
|
||||
}
|
||||
// or standard url
|
||||
return c.Redirect(302, "../")
|
||||
})
|
||||
groupAdmin.POST("/cnames/add", h.CreateCName)
|
||||
groupAdmin.GET("/cnames/delete/:id", h.DeleteCName)
|
||||
e.POST("/hosts/add", h.CreateHost)
|
||||
e.POST("/hosts/edit/:id", h.UpdateHost)
|
||||
e.GET("/hosts/delete/:id", h.DeleteHost)
|
||||
e.POST("/cnames/add", h.CreateCName)
|
||||
e.GET("/cnames/delete/:id", h.DeleteCName)
|
||||
|
||||
// dyndns compatible api
|
||||
// (avoid breaking changes and create groups for each update endpoint)
|
||||
updateRoute := e.Group("/update")
|
||||
updateRoute.Use(middleware.BasicAuth(h.AuthenticateUpdate))
|
||||
updateRoute.GET("", h.UpdateIP)
|
||||
nicRoute := e.Group("/nic")
|
||||
nicRoute.Use(middleware.BasicAuth(h.AuthenticateUpdate))
|
||||
nicRoute.GET("/update", h.UpdateIP)
|
||||
v2Route := e.Group("/v2")
|
||||
v2Route.Use(middleware.BasicAuth(h.AuthenticateUpdate))
|
||||
v2Route.GET("/update", h.UpdateIP)
|
||||
v3Route := e.Group("/v3")
|
||||
v3Route.Use(middleware.BasicAuth(h.AuthenticateUpdate))
|
||||
v3Route.GET("/update", h.UpdateIP)
|
||||
|
||||
// health-check
|
||||
e.GET("/ping", func(c echo.Context) error {
|
||||
u := &handler.Error{
|
||||
Message: "OK",
|
||||
}
|
||||
return c.JSON(http.StatusOK, u)
|
||||
})
|
||||
e.GET("/update", h.UpdateIP)
|
||||
e.GET("/nic/update", h.UpdateIP)
|
||||
e.GET("/v2/update", h.UpdateIP)
|
||||
e.GET("/v3/update", h.UpdateIP)
|
||||
|
||||
// Start server
|
||||
e.Logger.Fatal(e.Start(":8080"))
|
||||
|
|
|
@ -11,10 +11,10 @@ type Host struct {
|
|||
gorm.Model
|
||||
Hostname string `gorm:"unique_index:idx_host_domain;not null" form:"hostname" validate:"required,hostname"`
|
||||
Domain string `gorm:"unique_index:idx_host_domain;not null" form:"domain" validate:"required,hostname"`
|
||||
Ip string `form:"ip" validate:"omitempty,ipv4|ipv6"`
|
||||
Ip string `form:"ip" validate:"omitempty,ipv4"`
|
||||
Ttl int `form:"ttl" validate:"required,min=20,max=86400"`
|
||||
LastUpdate time.Time `form:"lastupdate"`
|
||||
UserName string `gorm:"unique" form:"username" validate:"min=3"`
|
||||
UserName string `gorm:"unique" form:"username" validate:"min=8"`
|
||||
Password string `form:"password" validate:"min=8"`
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package nswrapper
|
|||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/labstack/gommon/log"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -25,7 +25,7 @@ func GetIPType(ipAddr string) string {
|
|||
// GetCallerIP searches for the "real" IP senders has actually.
|
||||
// If its a private address we won't use it.
|
||||
func GetCallerIP(r *http.Request) (string, error) {
|
||||
log.Info("request", r.Header)
|
||||
fmt.Println("request", r.Header)
|
||||
for _, h := range []string{"X-Real-Ip", "X-Forwarded-For"} {
|
||||
addresses := strings.Split(r.Header.Get(h), ",")
|
||||
// march from right to left until we get a public address
|
||||
|
|
|
@ -4,15 +4,14 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/labstack/gommon/log"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// UpdateRecord builds a nsupdate file and updates a record by executing it with nsupdate.
|
||||
func UpdateRecord(hostname string, target string, addrType string, zone string, ttl int, enableWildcard bool) error {
|
||||
log.Info(fmt.Sprintf("%s record update request: %s -> %s", addrType, hostname, target))
|
||||
func UpdateRecord(hostname string, target string, addrType string, zone string, ttl int) error {
|
||||
fmt.Printf("%s record update request: %s -> %s\n", addrType, hostname, target)
|
||||
|
||||
f, err := ioutil.TempFile(os.TempDir(), "dyndns")
|
||||
if err != nil {
|
||||
|
@ -25,13 +24,7 @@ func UpdateRecord(hostname string, target string, addrType string, zone string,
|
|||
w.WriteString(fmt.Sprintf("server %s\n", "localhost"))
|
||||
w.WriteString(fmt.Sprintf("zone %s\n", zone))
|
||||
w.WriteString(fmt.Sprintf("update delete %s.%s %s\n", hostname, zone, addrType))
|
||||
if enableWildcard {
|
||||
w.WriteString(fmt.Sprintf("update delete %s.%s %s\n", "*."+hostname, zone, addrType))
|
||||
}
|
||||
w.WriteString(fmt.Sprintf("update add %s.%s %v %s %s\n", hostname, zone, ttl, addrType, target))
|
||||
if enableWildcard {
|
||||
w.WriteString(fmt.Sprintf("update add %s.%s %v %s %s\n", "*."+hostname, zone, ttl, addrType, target))
|
||||
}
|
||||
w.WriteString("send\n")
|
||||
|
||||
w.Flush()
|
||||
|
@ -55,7 +48,7 @@ func UpdateRecord(hostname string, target string, addrType string, zone string,
|
|||
}
|
||||
|
||||
// DeleteRecord builds a nsupdate file and deletes a record by executing it with nsupdate.
|
||||
func DeleteRecord(hostname string, zone string, enableWildcard bool) error {
|
||||
func DeleteRecord(hostname string, zone string) error {
|
||||
fmt.Printf("record delete request: %s\n", hostname)
|
||||
|
||||
f, err := ioutil.TempFile(os.TempDir(), "dyndns")
|
||||
|
@ -69,9 +62,6 @@ func DeleteRecord(hostname string, zone string, enableWildcard bool) error {
|
|||
w.WriteString(fmt.Sprintf("server %s\n", "localhost"))
|
||||
w.WriteString(fmt.Sprintf("zone %s\n", zone))
|
||||
w.WriteString(fmt.Sprintf("update delete %s.%s\n", hostname, zone))
|
||||
if enableWildcard {
|
||||
w.WriteString(fmt.Sprintf("update delete %s.%s\n", "*."+hostname, zone))
|
||||
}
|
||||
w.WriteString("send\n")
|
||||
|
||||
w.Flush()
|
||||
|
|
7
dyndns/static/css/bootstrap.min.css
vendored
7
dyndns/static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
7
dyndns/static/css/jquery-ui.min.css
vendored
7
dyndns/static/css/jquery-ui.min.css
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
|
@ -1,18 +1,18 @@
|
|||
$("button.addHost").click(function () {
|
||||
location.href='/admin/hosts/add';
|
||||
location.href='/hosts/add';
|
||||
});
|
||||
|
||||
$("button.editHost").click(function () {
|
||||
location.href='/admin/hosts/edit/' + $(this).attr('id');
|
||||
location.href='/hosts/edit/' + $(this).attr('id');
|
||||
});
|
||||
|
||||
$("button.deleteHost").click(function () {
|
||||
$.ajax({
|
||||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
type: 'GET',
|
||||
url: "/admin/hosts/delete/" + $(this).attr('id')
|
||||
url: "/hosts/delete/" + $(this).attr('id')
|
||||
}).done(function(data, textStatus, jqXHR) {
|
||||
location.href="/admin/hosts";
|
||||
location.href="/hosts";
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
alert("Error: " + $.parseJSON(jqXHR.responseText).message);
|
||||
location.reload()
|
||||
|
@ -20,7 +20,7 @@ $("button.deleteHost").click(function () {
|
|||
});
|
||||
|
||||
$("button.showHostLog").click(function () {
|
||||
location.href='/admin/logs/host/' + $(this).attr('id');
|
||||
location.href='/logs/host/' + $(this).attr('id');
|
||||
});
|
||||
|
||||
$("button.add, button.edit").click(function () {
|
||||
|
@ -53,9 +53,9 @@ $("button.add, button.edit").click(function () {
|
|||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
data: $('#editHostForm').serialize(),
|
||||
type: 'POST',
|
||||
url: '/admin/'+type+'/'+action+id,
|
||||
url: '/'+type+'/'+action+id,
|
||||
}).done(function(data, textStatus, jqXHR) {
|
||||
location.href="/admin/"+type;
|
||||
location.href="/"+type;
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
alert("Error: " + $.parseJSON(jqXHR.responseText).message);
|
||||
});
|
||||
|
@ -64,7 +64,6 @@ $("button.add, button.edit").click(function () {
|
|||
});
|
||||
|
||||
$("#logout").click(function (){
|
||||
//document.execCommand("ClearAuthenticationCache");
|
||||
try {
|
||||
// This is for Firefox
|
||||
$.ajax({
|
||||
|
@ -74,7 +73,7 @@ $("#logout").click(function (){
|
|||
password: 'reset',
|
||||
// If the return is 401, refresh the page to request new details.
|
||||
statusCode: { 401: function() {
|
||||
// document.location = document.location;
|
||||
document.location = document.location;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -84,23 +83,22 @@ $("#logout").click(function (){
|
|||
if (!document.execCommand("ClearAuthenticationCache")) {
|
||||
// exeCommand returns false if it didn't work (which happens in Chrome) so as a last
|
||||
// resort refresh the page providing new, invalid details.
|
||||
// document.location = location.protocol+"//reset:reset@" + document.location.hostname + document.location.pathname;
|
||||
document.location = "http://reset:reset@" + document.location.hostname + document.location.pathname;
|
||||
}
|
||||
}
|
||||
console.log("first logout")
|
||||
});
|
||||
|
||||
$("button.addCName").click(function () {
|
||||
location.href='/admin/cnames/add';
|
||||
location.href='/cnames/add';
|
||||
});
|
||||
|
||||
$("button.deleteCName").click(function () {
|
||||
$.ajax({
|
||||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
type: 'GET',
|
||||
url: "/admin/cnames/delete/" + $(this).attr('id')
|
||||
url: "/cnames/delete/" + $(this).attr('id')
|
||||
}).done(function(data, textStatus, jqXHR) {
|
||||
location.href="/admin/cnames";
|
||||
location.href="/cnames";
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
alert("Error: " + $.parseJSON(jqXHR.responseText).message);
|
||||
location.reload()
|
||||
|
@ -126,33 +124,15 @@ $("button.copyToClipboard").click(function () {
|
|||
copyText.setSelectionRange(0, 99999);
|
||||
document.execCommand("copy");
|
||||
});
|
||||
$("button.copyUrlToClipboard").click(function () {
|
||||
let id = $(this).attr('id');
|
||||
let hostname = document.getElementById('host-hostname_'+id).innerHTML
|
||||
let domain = document.getElementById('host-domain_'+id).innerHTML
|
||||
let username = document.getElementById('host-username_'+id).innerHTML
|
||||
let password = document.getElementById('host-password_'+id).innerHTML
|
||||
let out = location.protocol + '//' +username.trim()+':'+password.trim()+'@'+ domain
|
||||
out +='/update?hostname='+hostname
|
||||
|
||||
let dummy = document.createElement("textarea");
|
||||
document.body.appendChild(dummy);
|
||||
dummy.value = out;
|
||||
dummy.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(dummy);
|
||||
});
|
||||
|
||||
function randomHash() {
|
||||
let chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
var passwordLength = 16;
|
||||
var password = "";
|
||||
for (var i = 0; i <= passwordLength; i++) {
|
||||
var randomNumber = Math.floor(Math.random() * chars.length);
|
||||
password += chars.substring(randomNumber, randomNumber +1);
|
||||
let chars = "abcdefghijklmnopqrstuvwxyz!@#$%^&*()-+<>ABCDEFGHIJKLMNOP1234567890";
|
||||
let pass = "";
|
||||
for (let x = 0; x < 32; x++) {
|
||||
let i = Math.floor(Math.random() * chars.length);
|
||||
pass += chars.charAt(i);
|
||||
}
|
||||
|
||||
return password;
|
||||
return pass;
|
||||
}
|
||||
|
||||
$("button.generateHash").click(function () {
|
||||
|
@ -175,7 +155,7 @@ $(document).ready(function(){
|
|||
}
|
||||
});
|
||||
|
||||
urlPath = new URL(window.location.href).pathname.split("/")[2];
|
||||
urlPath = new URL(window.location.href).pathname.split("/")[1];
|
||||
if (urlPath === "") {
|
||||
urlPath = "hosts"
|
||||
}
|
||||
|
|
7
dyndns/static/js/bootstrap.min.js
vendored
7
dyndns/static/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
dyndns/static/js/jquery-3.4.1.min.js
vendored
2
dyndns/static/js/jquery-3.4.1.min.js
vendored
File diff suppressed because one or more lines are too long
13
dyndns/static/js/jquery-ui.min.js
vendored
13
dyndns/static/js/jquery-ui.min.js
vendored
File diff suppressed because one or more lines are too long
5
dyndns/static/js/popper.min.js
vendored
5
dyndns/static/js/popper.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -7,13 +7,13 @@
|
|||
<meta name="author" content="">
|
||||
<link rel="icon" href="/static/icons/favicon.ico">
|
||||
|
||||
<title>{{.title}}</title>
|
||||
<title>TheBBCloud DynDNS</title>
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||
|
||||
<!-- JQueryUI base CSS -->
|
||||
<link rel="stylesheet" href="/static/css/jquery-ui.min.css"/>
|
||||
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.min.css" integrity="sha256-sEGfrwMkIjbgTBwGLVK38BG/XwIiNC/EAG9Rzsfda6A=" crossorigin="anonymous" />
|
||||
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="/static/css/narrow-jumbotron.css" rel="stylesheet">
|
||||
|
@ -27,27 +27,27 @@
|
|||
<nav>
|
||||
<ul class="nav nav-pills float-right">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link nav-hosts" href="/admin/hosts">Hosts</a>
|
||||
<a class="nav-link nav-hosts" href="/hosts">Hosts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link nav-cnames" href="/admin/cnames">CNames</a>
|
||||
<a class="nav-link nav-cnames" href="/cnames">CNames</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link nav-logs" href="/admin/logs">Logs</a>
|
||||
<a class="nav-link nav-logs" href="/logs">Logs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link nav-logout" href="/admin/logout" id="logout">Logout</a>
|
||||
<a class="nav-link nav-logout" href="" id="logout">Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h3 class="text-muted">{{.title}}</h3>
|
||||
<h3 class="text-muted">TheBBCloud DynDNS</h3>
|
||||
</div>
|
||||
|
||||
<!-- Page Content -->
|
||||
{{template "content" .}}
|
||||
|
||||
<footer class="footer">
|
||||
<p>© {{.title}} {{year}}</p>
|
||||
<p>© TheBBCloud 2021</p>
|
||||
</footer>
|
||||
|
||||
</div> <!-- /container -->
|
||||
|
@ -56,11 +56,10 @@
|
|||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
||||
<script src="/static/js/jquery-3.4.1.min.js"></script>
|
||||
<!-- popper.js@1.16.0 -->
|
||||
<script src="/static/js/popper.min.js"></script>
|
||||
<script src="/static/js/bootstrap.min.js"></script>
|
||||
<script src="/static/js/jquery-ui.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
|
||||
<script src="/static/js/actions-1.0.0.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,54 +1,27 @@
|
|||
{{define "content"}}
|
||||
<div class="container marketing">
|
||||
<h3 class="text-center mb-4">DNS Host Entries</h3>
|
||||
<table class="table table-striped text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>Hostname</th>
|
||||
<th>IP</th>
|
||||
<th>TTL</th>
|
||||
<th>LastUpdate</th>
|
||||
<th>
|
||||
<button class="addHost btn btn-primary">Add Host Entry</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .hosts}}
|
||||
<tr id="host_{{.ID}}">
|
||||
<td id="host-domain_{{.ID}}">{{.Domain}}</td>
|
||||
<td id="host-hostname_{{.ID}}">{{.Hostname}}.{{.Domain}}</td>
|
||||
<td>{{.Ip}}</td>
|
||||
<td>{{.Ttl}}</td>
|
||||
<td>{{.LastUpdate.Format "01/02/2006 15:04 MEZ"}}</td>
|
||||
<td>
|
||||
<div style="display:none">
|
||||
<div id="host-username_{{.ID}}">
|
||||
{{.UserName}}
|
||||
</div>
|
||||
<div id="host-password_{{.ID}}" >
|
||||
{{.Password}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group" id="host_{{.ID}}" >
|
||||
<button id="{{.ID}}" class="editHost btn btn-outline-secondary btn-sm"><img
|
||||
src="/static/icons/pencil.svg" alt="" width="16" height="16" title="Edit"></button>
|
||||
<button
|
||||
id="{{.ID}}" class="deleteHost btn btn-outline-secondary btn-sm"><img
|
||||
src="/static/icons/trash.svg"
|
||||
alt="" width="16" height="16"
|
||||
title="Delete"></button>
|
||||
<button id="{{.ID}}" class="showHostLog btn btn-outline-secondary btn-sm"><img
|
||||
src="/static/icons/table.svg" alt="" width="16" height="16" title="Logs"></button>
|
||||
<button id="{{.ID}}" class="copyUrlToClipboard btn btn-outline-secondary btn-sm"><img
|
||||
src="/static/icons/clipboard.svg" alt="" width="16" height="16" title="Copy URL to clipboard"></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="container marketing">
|
||||
<h3 class="text-center mb-4">DNS Host Entries</h3>
|
||||
<table class="table table-striped text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>IP</th>
|
||||
<th>TTL</th>
|
||||
<th>LastUpdate</th>
|
||||
<th><button class="addHost btn btn-primary">Add Host Entry</button></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .hosts}}
|
||||
<tr>
|
||||
<td>{{.Hostname}}.{{.Domain}}</td>
|
||||
<td>{{.Ip}}</td>
|
||||
<td>{{.Ttl}}</td>
|
||||
<td>{{.LastUpdate.Format "01/02/2006 15:04 MEZ"}}</td>
|
||||
<td><button id="{{.ID}}" class="editHost btn btn-outline-secondary btn-sm"><img src="/static/icons/pencil.svg" alt="" width="16" height="16" title="Edit"></button> <button id="{{.ID}}" class="deleteHost btn btn-outline-secondary btn-sm"><img src="/static/icons/trash.svg" alt="" width="16" height="16" title="Delete"></button> <button id="{{.ID}}" class="showHostLog btn btn-outline-secondary btn-sm"><img src="/static/icons/table.svg" alt="" width="16" height="16" title="Logs"></button></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
Loading…
Add table
Reference in a new issue