Rename zone in domain
This commit is contained in:
parent
898e5ed5c8
commit
fa2ed5133f
209
api/domains.go
Normal file
209
api/domains.go
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
|
"git.happydns.org/happydns/config"
|
||||||
|
"git.happydns.org/happydns/model"
|
||||||
|
"git.happydns.org/happydns/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.GET("/api/domains", apiAuthHandler(getDomains))
|
||||||
|
router.POST("/api/domains", apiAuthHandler(addDomain))
|
||||||
|
router.DELETE("/api/domains/:domain", apiAuthHandler(domainHandler(delDomain)))
|
||||||
|
router.GET("/api/domains/:domain", apiAuthHandler(domainHandler(getDomain)))
|
||||||
|
router.GET("/api/domains/:domain/rr", apiAuthHandler(domainHandler(axfrDomain)))
|
||||||
|
router.POST("/api/domains/:domain/rr", apiAuthHandler(domainHandler(addRR)))
|
||||||
|
router.DELETE("/api/domains/:domain/rr", apiAuthHandler(domainHandler(delRR)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDomains(_ *config.Options, u *happydns.User, p httprouter.Params, body io.Reader) Response {
|
||||||
|
if domains, err := storage.MainStore.GetDomains(u); err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return APIResponse{
|
||||||
|
response: domains,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addDomain(_ *config.Options, u *happydns.User, p httprouter.Params, body io.Reader) Response {
|
||||||
|
var uz happydns.Domain
|
||||||
|
err := json.NewDecoder(body).Decode(&uz)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uz.DomainName) <= 2 {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: errors.New("The given domain is invalid."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if uz.DomainName[len(uz.DomainName)-1] != '.' {
|
||||||
|
uz.DomainName = uz.DomainName + "."
|
||||||
|
}
|
||||||
|
|
||||||
|
if storage.MainStore.DomainExists(uz.DomainName) {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: errors.New("This domain already exists."),
|
||||||
|
}
|
||||||
|
} else if err := storage.MainStore.CreateDomain(u, &uz); err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return APIResponse{
|
||||||
|
response: uz,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func delDomain(_ *config.Options, domain *happydns.Domain, body io.Reader) Response {
|
||||||
|
if err := storage.MainStore.DeleteDomain(domain); err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return APIResponse{
|
||||||
|
response: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func domainHandler(f func(*config.Options, *happydns.Domain, io.Reader) Response) func(*config.Options, *happydns.User, httprouter.Params, io.Reader) Response {
|
||||||
|
return func(opts *config.Options, u *happydns.User, ps httprouter.Params, body io.Reader) Response {
|
||||||
|
if domain, err := storage.MainStore.GetDomainByDN(u, ps.ByName("domain")); err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
status: http.StatusNotFound,
|
||||||
|
err: errors.New("Domain not found"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return f(opts, domain, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDomain(_ *config.Options, domain *happydns.Domain, body io.Reader) Response {
|
||||||
|
return APIResponse{
|
||||||
|
response: domain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func axfrDomain(opts *config.Options, domain *happydns.Domain, body io.Reader) Response {
|
||||||
|
source, err := storage.MainStore.GetSource(&happydns.User{Id: domain.IdUser}, domain.IdSource)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rrs, err := source.ImportZone(domain)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret []map[string]interface{}
|
||||||
|
for _, rr := range rrs {
|
||||||
|
ret = append(ret, map[string]interface{}{
|
||||||
|
"string": rr.String(),
|
||||||
|
"fields": rr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return APIResponse{
|
||||||
|
response: ret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type uploadedRR struct {
|
||||||
|
RR string `json:"string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRR(opts *config.Options, domain *happydns.Domain, body io.Reader) Response {
|
||||||
|
var urr uploadedRR
|
||||||
|
err := json.NewDecoder(body).Decode(&urr)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rr, err := dns.NewRR(fmt.Sprintf("$ORIGIN %s\n$TTL %d\n%s", domain.DomainName, 3600, urr.RR))
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source, err := storage.MainStore.GetSource(&happydns.User{Id: domain.IdUser}, domain.IdSource)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = source.AddRR(domain, rr)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
status: http.StatusInternalServerError,
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return APIResponse{
|
||||||
|
response: map[string]interface{}{
|
||||||
|
"string": rr.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func delRR(opts *config.Options, domain *happydns.Domain, body io.Reader) Response {
|
||||||
|
var urr uploadedRR
|
||||||
|
err := json.NewDecoder(body).Decode(&urr)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rr, err := dns.NewRR(urr.RR)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source, err := storage.MainStore.GetSource(&happydns.User{Id: domain.IdUser}, domain.IdSource)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = source.DeleteRR(domain, rr)
|
||||||
|
if err != nil {
|
||||||
|
return APIErrorResponse{
|
||||||
|
status: http.StatusInternalServerError,
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return APIResponse{
|
||||||
|
response: true,
|
||||||
|
}
|
||||||
|
}
|
264
api/zones.go
264
api/zones.go
|
@ -1,264 +0,0 @@
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
|
|
||||||
"git.happydns.org/happydns/config"
|
|
||||||
"git.happydns.org/happydns/model"
|
|
||||||
"git.happydns.org/happydns/storage"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
router.GET("/api/zones", apiAuthHandler(getZones))
|
|
||||||
router.POST("/api/zones", apiAuthHandler(addZone))
|
|
||||||
router.DELETE("/api/zones/:zone", apiAuthHandler(zoneHandler(delZone)))
|
|
||||||
router.GET("/api/zones/:zone", apiAuthHandler(zoneHandler(getZone)))
|
|
||||||
router.GET("/api/zones/:zone/rr", apiAuthHandler(zoneHandler(axfrZone)))
|
|
||||||
router.POST("/api/zones/:zone/rr", apiAuthHandler(zoneHandler(addRR)))
|
|
||||||
router.DELETE("/api/zones/:zone/rr", apiAuthHandler(zoneHandler(delRR)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getZones(_ *config.Options, u *happydns.User, p httprouter.Params, body io.Reader) Response {
|
|
||||||
if zones, err := storage.MainStore.GetZones(u); err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return APIResponse{
|
|
||||||
response: zones,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addZone(_ *config.Options, u *happydns.User, p httprouter.Params, body io.Reader) Response {
|
|
||||||
var uz happydns.Zone
|
|
||||||
err := json.NewDecoder(body).Decode(&uz)
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(uz.DomainName) <= 2 {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: errors.New("The given zone is invalid."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if uz.DomainName[len(uz.DomainName)-1] != '.' {
|
|
||||||
uz.DomainName = uz.DomainName + "."
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(uz.KeyName) > 1 && uz.KeyName[len(uz.KeyName)-1] != '.' {
|
|
||||||
uz.KeyName = uz.KeyName + "."
|
|
||||||
}
|
|
||||||
|
|
||||||
if storage.MainStore.ZoneExists(uz.DomainName) {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: errors.New("This zone already exists."),
|
|
||||||
}
|
|
||||||
} else if err := storage.MainStore.CreateZone(u, &uz); err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return APIResponse{
|
|
||||||
response: uz,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func delZone(_ *config.Options, zone *happydns.Zone, body io.Reader) Response {
|
|
||||||
if err := storage.MainStore.DeleteZone(zone); err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return APIResponse{
|
|
||||||
response: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func zoneHandler(f func(*config.Options, *happydns.Zone, io.Reader) Response) func(*config.Options, *happydns.User, httprouter.Params, io.Reader) Response {
|
|
||||||
return func(opts *config.Options, u *happydns.User, ps httprouter.Params, body io.Reader) Response {
|
|
||||||
if zone, err := storage.MainStore.GetZoneByDN(u, ps.ByName("zone")); err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
status: http.StatusNotFound,
|
|
||||||
err: errors.New("Domain not found"),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return f(opts, zone, body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getZone(_ *config.Options, zone *happydns.Zone, body io.Reader) Response {
|
|
||||||
return APIResponse{
|
|
||||||
response: zone,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeNSServer(opts *config.Options, srv string) string {
|
|
||||||
if srv == "" {
|
|
||||||
return opts.DefaultNameServer
|
|
||||||
} else if strings.Index(srv, ":") > -1 {
|
|
||||||
return srv
|
|
||||||
} else {
|
|
||||||
return srv + ":53"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func axfrZone(opts *config.Options, zone *happydns.Zone, body io.Reader) Response {
|
|
||||||
d := net.Dialer{}
|
|
||||||
con, err := d.Dial("tcp", normalizeNSServer(opts, zone.Server))
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
status: http.StatusInternalServerError,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defer con.Close()
|
|
||||||
|
|
||||||
m := new(dns.Msg)
|
|
||||||
m.SetEdns0(4096, true)
|
|
||||||
m.SetAxfr(zone.DomainName)
|
|
||||||
m.SetTsig(zone.KeyName, zone.KeyAlgo, 300, time.Now().Unix())
|
|
||||||
|
|
||||||
dnscon := &dns.Conn{Conn: con}
|
|
||||||
transfer := &dns.Transfer{Conn: dnscon, TsigSecret: map[string]string{zone.KeyName: zone.Base64KeyBlob()}}
|
|
||||||
c, err := transfer.In(m, normalizeNSServer(opts, zone.Server))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
status: http.StatusInternalServerError,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var rrs []map[string]interface{}
|
|
||||||
for {
|
|
||||||
response, ok := <-c
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rr := range response.RR {
|
|
||||||
rrs = append(rrs, map[string]interface{}{
|
|
||||||
"string": rr.String(),
|
|
||||||
"fields": rr,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rrs) > 0 {
|
|
||||||
rrs = rrs[0 : len(rrs)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return APIResponse{
|
|
||||||
response: rrs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type uploadedRR struct {
|
|
||||||
RR string `json:"string"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func addRR(opts *config.Options, zone *happydns.Zone, body io.Reader) Response {
|
|
||||||
var urr uploadedRR
|
|
||||||
err := json.NewDecoder(body).Decode(&urr)
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rr, err := dns.NewRR(fmt.Sprintf("$ORIGIN %s\n$TTL %d\n%s", zone.DomainName, 3600, urr.RR))
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m := new(dns.Msg)
|
|
||||||
m.Id = dns.Id()
|
|
||||||
m.Opcode = dns.OpcodeUpdate
|
|
||||||
m.Question = make([]dns.Question, 1)
|
|
||||||
m.Question[0] = dns.Question{zone.DomainName, dns.TypeSOA, dns.ClassINET}
|
|
||||||
|
|
||||||
m.Insert([]dns.RR{rr})
|
|
||||||
|
|
||||||
c := new(dns.Client)
|
|
||||||
c.TsigSecret = map[string]string{zone.KeyName: zone.Base64KeyBlob()}
|
|
||||||
m.SetTsig(zone.KeyName, zone.KeyAlgo, 300, time.Now().Unix())
|
|
||||||
|
|
||||||
in, rtt, err := c.Exchange(m, normalizeNSServer(opts, zone.Server))
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
status: http.StatusInternalServerError,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return APIResponse{
|
|
||||||
response: map[string]interface{}{
|
|
||||||
"in": *in,
|
|
||||||
"rtt": rtt,
|
|
||||||
"string": rr.String(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func delRR(opts *config.Options, zone *happydns.Zone, body io.Reader) Response {
|
|
||||||
var urr uploadedRR
|
|
||||||
err := json.NewDecoder(body).Decode(&urr)
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rr, err := dns.NewRR(urr.RR)
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m := new(dns.Msg)
|
|
||||||
m.Id = dns.Id()
|
|
||||||
m.Opcode = dns.OpcodeUpdate
|
|
||||||
m.Question = make([]dns.Question, 1)
|
|
||||||
m.Question[0] = dns.Question{zone.DomainName, dns.TypeSOA, dns.ClassINET}
|
|
||||||
|
|
||||||
m.Remove([]dns.RR{rr})
|
|
||||||
|
|
||||||
c := new(dns.Client)
|
|
||||||
c.TsigSecret = map[string]string{zone.KeyName: zone.Base64KeyBlob()}
|
|
||||||
m.SetTsig(zone.KeyName, zone.KeyAlgo, 300, time.Now().Unix())
|
|
||||||
|
|
||||||
in, rtt, err := c.Exchange(m, normalizeNSServer(opts, zone.Server))
|
|
||||||
if err != nil {
|
|
||||||
return APIErrorResponse{
|
|
||||||
status: http.StatusInternalServerError,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return APIResponse{
|
|
||||||
response: map[string]interface{}{
|
|
||||||
"in": *in,
|
|
||||||
"rtt": rtt,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -26,39 +26,39 @@ const routes = [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/zones',
|
path: '/domains',
|
||||||
name: 'zones',
|
name: 'domains',
|
||||||
component: function () {
|
component: function () {
|
||||||
return import(/* webpackChunkName: "zone-list" */ '../views/zone-list.vue')
|
return import(/* webpackChunkName: "domain-list" */ '../views/domain-list.vue')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/zones/:zone',
|
path: '/domains/:zone',
|
||||||
component: function () {
|
component: function () {
|
||||||
return import(/* webpackChunkName: "zone" */ '../views/zone.vue')
|
return import(/* webpackChunkName: "domain" */ '../views/domain.vue')
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: 'zone',
|
name: 'domain-source',
|
||||||
component: function () {
|
component: function () {
|
||||||
return import(/* webpackChunkName: "zone" */ '../views/zone-details.vue')
|
return import(/* webpackChunkName: "domain-source" */ '../views/domain-source.vue')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'services',
|
path: 'services',
|
||||||
name: 'zone-services',
|
name: 'zone-services',
|
||||||
component: function () {
|
component: function () {
|
||||||
return import(/* webpackChunkName: "zone" */ '../views/zone-services.vue')
|
return import(/* webpackChunkName: "zone-services" */ '../views/zone-services.vue')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/zones/:zone/records',
|
path: '/zones/:domain/records',
|
||||||
name: 'zone-records',
|
name: 'zone-records',
|
||||||
component: function () {
|
component: function () {
|
||||||
return import(/* webpackChunkName: "zone" */ '../views/zone-records.vue')
|
return import(/* webpackChunkName: "zone-records" */ '../views/zone-records.vue')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Home from '@/views/Home'
|
import Home from '@/views/Home'
|
||||||
import ZoneList from '@/views/zone-list'
|
import ZoneList from '@/views/domain-list'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data () {
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
<div class="offset-md-2 col-md-8">
|
<div class="offset-md-2 col-md-8">
|
||||||
<b-list-group>
|
<b-list-group>
|
||||||
<b-list-group-item v-if="loading" class="text-center">
|
<b-list-group-item v-if="loading" class="text-center">
|
||||||
<b-spinner variant="secondary" label="Spinning"></b-spinner> Retrieving your zones...
|
<b-spinner variant="secondary" label="Spinning"></b-spinner> Retrieving your domains...
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
<b-list-group-item :to="'zones/' + zone.domain" v-for="(zone, index) in zones" v-bind:key="index" class="d-flex justify-content-between align-items-center">
|
<b-list-group-item :to="'domains/' + domain.domain" v-for="(domain, index) in domains" v-bind:key="index" class="d-flex justify-content-between align-items-center">
|
||||||
{{ zone.domain }}
|
{{ domain.domain }}
|
||||||
<b-badge variant="success">OK</b-badge>
|
<b-badge variant="success">OK</b-badge>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
</b-list-group>
|
</b-list-group>
|
||||||
|
@ -19,9 +19,9 @@
|
||||||
<b-input-group-prepend>
|
<b-input-group-prepend>
|
||||||
<b-icon icon="plus"></b-icon>
|
<b-icon icon="plus"></b-icon>
|
||||||
</b-input-group-prepend>
|
</b-input-group-prepend>
|
||||||
<input placeholder="my.new.zone" v-model="newForm.domain" style="border:none; flex: 1 1 auto;">
|
<input placeholder="my.new.domain" v-model="newForm.domain" style="border:none; flex: 1 1 auto;">
|
||||||
<b-input-group-append v-show="newForm.domain.length">
|
<b-input-group-append v-show="newForm.domain.length">
|
||||||
<b-button type="submit" variant="outline-primary">Add new zone</b-button>
|
<b-button type="submit" variant="outline-primary">Add new domain</b-button>
|
||||||
</b-input-group-append>
|
</b-input-group-append>
|
||||||
</b-input-group>
|
</b-input-group>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
|
@ -31,9 +31,9 @@
|
||||||
</b-row>
|
</b-row>
|
||||||
|
|
||||||
<b-modal
|
<b-modal
|
||||||
id="newZoneModal"
|
id="newDomainModal"
|
||||||
ref="modal"
|
ref="modal"
|
||||||
title="Attach new zone"
|
title="Attach new domain"
|
||||||
@show="resetModal"
|
@show="resetModal"
|
||||||
@shown="modalShown"
|
@shown="modalShown"
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
|
@ -115,25 +115,25 @@ export default {
|
||||||
domainNameState: null,
|
domainNameState: null,
|
||||||
loading: true,
|
loading: true,
|
||||||
newForm: { domain: '', storage_facility: 'live' },
|
newForm: { domain: '', storage_facility: 'live' },
|
||||||
zones: []
|
domains: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted () {
|
mounted () {
|
||||||
setTimeout(() =>
|
setTimeout(() =>
|
||||||
axios
|
axios
|
||||||
.get('/api/zones')
|
.get('/api/domains')
|
||||||
.then(response => { this.zones = response.data; this.loading = false; return true })
|
.then(response => { this.domains = response.data; this.loading = false; return true })
|
||||||
, 100)
|
, 100)
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
show (zone) {
|
show (domain) {
|
||||||
this.$router.push('/zones/' + zone.domain)
|
this.$router.push('/domains/' + domain.domain)
|
||||||
},
|
},
|
||||||
|
|
||||||
showModal () {
|
showModal () {
|
||||||
this.$bvModal.show('newZoneModal')
|
this.$bvModal.show('newDomainModal')
|
||||||
},
|
},
|
||||||
|
|
||||||
modalShown () {
|
modalShown () {
|
||||||
|
@ -162,9 +162,9 @@ export default {
|
||||||
this.handleSubmit()
|
this.handleSubmit()
|
||||||
},
|
},
|
||||||
|
|
||||||
attachZone () {
|
attachDomain () {
|
||||||
axios
|
axios
|
||||||
.post('/api/zones', {
|
.post('/api/domains', {
|
||||||
domain: this.newForm.domain,
|
domain: this.newForm.domain,
|
||||||
server: this.newForm.server,
|
server: this.newForm.server,
|
||||||
keyname: this.newForm.keyname,
|
keyname: this.newForm.keyname,
|
||||||
|
@ -173,11 +173,11 @@ export default {
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
(response) => {
|
(response) => {
|
||||||
if (this.zones == null) this.zones = []
|
if (this.domains == null) this.domains = []
|
||||||
this.zones.push(response.data)
|
this.domains.push(response.data)
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
alert('Unable to attach the given zone: ' + error.response.data.errmsg)
|
alert('Unable to attach the given domain: ' + error.response.data.errmsg)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -187,7 +187,7 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.attachZone()
|
this.attachDomain()
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.modal.hide()
|
this.$refs.modal.hide()
|
69
htdocs/src/views/domain.vue
Normal file
69
htdocs/src/views/domain.vue
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<b-container class="mt-2">
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="3" class="text-right" style="background-color: #EAFFEC">
|
||||||
|
<router-link to="/domains/" class="btn font-weight-bolder"><b-icon icon="chevron-up"></b-icon></router-link>
|
||||||
|
</b-col>
|
||||||
|
<b-col cols="9">
|
||||||
|
<h2 class="mt-2 mb-3">
|
||||||
|
{{ domain.domain }}
|
||||||
|
</h2>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-alert variant="danger" :show="error.length != 0"><strong>Error:</strong> {{ error }}</b-alert>
|
||||||
|
<div class="text-center" v-if="!domain && error.length == 0">
|
||||||
|
<b-spinner label="Spinning"></b-spinner>
|
||||||
|
<p>Loading the domain …</p>
|
||||||
|
</div>
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="3" style="background-color: #EAFFEC">
|
||||||
|
<b-navbar class="flex-column">
|
||||||
|
<b-nav pills vertical>
|
||||||
|
<b-nav-item :to="'/domains/' + domain.domain" :active="$route.name == 'domain-source'">Domain source</b-nav-item>
|
||||||
|
<b-nav-item :to="'/domains/' + domain.domain + '/services'" :active="$route.name == 'zone-services'">View services</b-nav-item>
|
||||||
|
<b-nav-item :to="'/zones/' + domain.domain + '/records'" :active="$route.name == 'zone-records'">View records</b-nav-item>
|
||||||
|
<b-nav-item :to="'/domain/' + domain.domain + '/monitoring'" :active="$route.name == 'domain-monitoring'">Monitoring</b-nav-item>
|
||||||
|
<hr>
|
||||||
|
<b-nav-form>
|
||||||
|
<b-button type="button" @click="detachDomain()" variant="outline-danger"><b-icon icon="trash-fill"></b-icon> Stop managing this domain</b-button>
|
||||||
|
</b-nav-form>
|
||||||
|
</b-nav>
|
||||||
|
</b-navbar>
|
||||||
|
</b-col>
|
||||||
|
<b-col cols="9">
|
||||||
|
<router-view :domain="domain"></router-view>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</b-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
error: '',
|
||||||
|
domain: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
var mydomain = this.$route.params.domain
|
||||||
|
axios
|
||||||
|
.get('/api/domains/' + mydomain)
|
||||||
|
.then(response => (this.domain = response.data))
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
detachDomain () {
|
||||||
|
axios
|
||||||
|
.delete('/api/domains/' + this.domain.domain)
|
||||||
|
.then(response => (
|
||||||
|
this.$router.push('/domains/')
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -5,8 +5,8 @@
|
||||||
<b-button-group v-show="rrs && rrs.length" class="float-right ml-2" size="sm" variant="secondary">
|
<b-button-group v-show="rrs && rrs.length" class="float-right ml-2" size="sm" variant="secondary">
|
||||||
<b-button :pressed.sync="showDNSSEC">DNSSEC</b-button>
|
<b-button :pressed.sync="showDNSSEC">DNSSEC</b-button>
|
||||||
</b-button-group>
|
</b-button-group>
|
||||||
<router-link :to="'/zones/' + zone.domain" class="btn"><b-icon icon="chevron-left"></b-icon></router-link>
|
<router-link :to="'/domains/' + domain.domain" class="btn"><b-icon icon="chevron-left"></b-icon></router-link>
|
||||||
{{ zone.domain }}
|
{{ domain.domain }}
|
||||||
<small class="text-muted">Resource Records <span v-if="rrs && rrs.length">({{ rrsFiltered.length }}/{{ rrs.length }})</span></small>
|
<small class="text-muted">Resource Records <span v-if="rrs && rrs.length">({{ rrsFiltered.length }}/{{ rrs.length }})</span></small>
|
||||||
</h2>
|
</h2>
|
||||||
<b-alert variant="danger" :show="error.length != 0"><strong>Error:</strong> {{ error }}</b-alert>
|
<b-alert variant="danger" :show="error.length != 0"><strong>Error:</strong> {{ error }}</b-alert>
|
||||||
|
@ -74,7 +74,7 @@ export default {
|
||||||
expandrrs: {},
|
expandrrs: {},
|
||||||
rrs: [],
|
rrs: [],
|
||||||
query: '',
|
query: '',
|
||||||
zone: {}
|
domain: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -94,13 +94,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted () {
|
mounted () {
|
||||||
var myzone = this.$route.params.zone
|
var mydomain = this.$route.params.domain
|
||||||
axios
|
axios
|
||||||
.get('/api/zones/' + myzone)
|
.get('/api/domains/' + mydomain)
|
||||||
.then(response => (this.zone = response.data))
|
.then(response => (this.domain = response.data))
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.get('/api/zones/' + myzone + '/rr')
|
.get('/api/domains/' + mydomain + '/rr')
|
||||||
.then(
|
.then(
|
||||||
(response) => (this.rrs = response.data),
|
(response) => (this.rrs = response.data),
|
||||||
(error) => (this.error = error.response.data.errmsg)
|
(error) => (this.error = error.response.data.errmsg)
|
||||||
|
@ -119,24 +119,24 @@ export default {
|
||||||
|
|
||||||
newRR (idx) {
|
newRR (idx) {
|
||||||
axios
|
axios
|
||||||
.post('/api/zones/' + this.$route.params.zone + '/rr', {
|
.post('/api/domains/' + this.$route.params.domain + '/rr', {
|
||||||
string: this.rrsFiltered[idx].string
|
string: this.rrsFiltered[idx].string
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
(response) => {
|
(response) => {
|
||||||
axios
|
axios
|
||||||
.get('/api/zones/' + this.$route.params.zone + '/rr')
|
.get('/api/domains/' + this.$route.params.domain + '/rr')
|
||||||
.then(response => (this.rrs = response.data))
|
.then(response => (this.rrs = response.data))
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
alert('An error occurs when trying to add RR to zone: ' + error.response.data.errmsg)
|
alert('An error occurs when trying to add RR to the zone: ' + error.response.data.errmsg)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteRR (idx) {
|
deleteRR (idx) {
|
||||||
axios
|
axios
|
||||||
.delete('/api/zones/' + this.$route.params.zone + '/rr', {
|
.delete('/api/domains/' + this.$route.params.domain + '/rr', {
|
||||||
data: {
|
data: {
|
||||||
string: this.rrsFiltered[idx].string
|
string: this.rrsFiltered[idx].string
|
||||||
}
|
}
|
||||||
|
@ -144,11 +144,11 @@ export default {
|
||||||
.then(
|
.then(
|
||||||
(response) => {
|
(response) => {
|
||||||
axios
|
axios
|
||||||
.get('/api/zones/' + this.$route.params.zone + '/rr')
|
.get('/api/domains/' + this.$route.params.domain + '/rr')
|
||||||
.then(response => (this.rrs = response.data))
|
.then(response => (this.rrs = response.data))
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
alert('An error occurs when trying to delete RR in zone: ' + error.response.data.errmsg)
|
alert('An error occurs when trying to delete RR in the zone: ' + error.response.data.errmsg)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
<template>
|
|
||||||
<b-container class="mt-2">
|
|
||||||
<b-row>
|
|
||||||
<b-col cols="3" class="text-right" style="background-color: #EAFFEC">
|
|
||||||
<router-link to="/zones/" class="btn font-weight-bolder"><b-icon icon="chevron-up"></b-icon></router-link>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="9">
|
|
||||||
<h2 class="mt-2 mb-3">
|
|
||||||
{{ zone.domain }}
|
|
||||||
</h2>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-alert variant="danger" :show="error.length != 0"><strong>Error:</strong> {{ error }}</b-alert>
|
|
||||||
<div class="text-center" v-if="!zone && error.length == 0">
|
|
||||||
<b-spinner label="Spinning"></b-spinner>
|
|
||||||
<p>Loading the zone …</p>
|
|
||||||
</div>
|
|
||||||
<b-row>
|
|
||||||
<b-col cols="3" style="background-color: #EAFFEC">
|
|
||||||
<b-navbar class="flex-column">
|
|
||||||
<b-nav pills vertical>
|
|
||||||
<b-nav-item :to="'/zones/' + zone.domain" :active="$route.name == 'zone'">My zone</b-nav-item>
|
|
||||||
<b-nav-item :to="'/zones/' + zone.domain + '/services'" :active="$route.name == 'zone-services'">View services</b-nav-item>
|
|
||||||
<b-nav-item :to="'/zones/' + zone.domain + '/records'" :active="$route.name == 'zone-records'">View records</b-nav-item>
|
|
||||||
<b-nav-item :to="'/zones/' + zone.domain + '/monitoring'" :active="$route.name == 'zone-monitoring'">Monitoring</b-nav-item>
|
|
||||||
<hr>
|
|
||||||
<b-nav-form>
|
|
||||||
<b-button type="button" @click="deleteZone(zone)" variant="outline-danger"><b-icon icon="trash-fill"></b-icon> Delete my zone</b-button>
|
|
||||||
</b-nav-form>
|
|
||||||
</b-nav>
|
|
||||||
</b-navbar>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="9">
|
|
||||||
<router-view></router-view>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
error: '',
|
|
||||||
zone: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
var myzone = this.$route.params.zone
|
|
||||||
axios
|
|
||||||
.get('/api/zones/' + myzone)
|
|
||||||
.then(response => (this.zone = response.data))
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
deleteZone (zone) {
|
|
||||||
axios
|
|
||||||
.delete('/api/zones/' + zone.domain)
|
|
||||||
.then(response => (
|
|
||||||
axios
|
|
||||||
.get('/api/zones')
|
|
||||||
.then(response => {
|
|
||||||
this.zones = response.data
|
|
||||||
this.$router.go('/zones/')
|
|
||||||
})
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
34
model/domain.go
Normal file
34
model/domain.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package happydns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Domain struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdUser int64
|
||||||
|
IdSource int64
|
||||||
|
DomainName string `json:"domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Domains []*Domain
|
||||||
|
|
||||||
|
func (d *Domain) NormalizedNSServer() string {
|
||||||
|
if strings.Index(d.DomainName, ":") > -1 {
|
||||||
|
return d.DomainName
|
||||||
|
} else {
|
||||||
|
return d.DomainName + ":53"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDomain(u *User, s Source, dn string) (d *Domain) {
|
||||||
|
d = &Domain{
|
||||||
|
IdUser: u.Id,
|
||||||
|
//IdSource: s.GetId(),
|
||||||
|
DomainName: dn,
|
||||||
|
}
|
||||||
|
|
||||||
|
d.DomainName = d.NormalizedNSServer()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
package happydns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Zone struct {
|
|
||||||
Id int64 `json:"id"`
|
|
||||||
IdUser int64
|
|
||||||
DomainName string `json:"domain"`
|
|
||||||
Server string `json:"server,omitempty"`
|
|
||||||
KeyName string `json:"keyname,omitempty"`
|
|
||||||
KeyAlgo string `json:"algorithm,omitempty"`
|
|
||||||
KeyBlob []byte `json:"keyblob,omitempty"`
|
|
||||||
StorageFacility string `json:"storage_facility,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Zones []*Zone
|
|
||||||
|
|
||||||
func NewZone(u User, dn, server, keyname, algo string, keyblob []byte, storage string) *Zone {
|
|
||||||
return &Zone{
|
|
||||||
IdUser: u.Id,
|
|
||||||
DomainName: dn,
|
|
||||||
Server: server,
|
|
||||||
KeyName: keyname,
|
|
||||||
KeyAlgo: algo,
|
|
||||||
KeyBlob: keyblob,
|
|
||||||
StorageFacility: storage,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Zone) Base64KeyBlob() string {
|
|
||||||
return base64.StdEncoding.EncodeToString(z.KeyBlob)
|
|
||||||
}
|
|
14
static.go
14
static.go
|
@ -33,6 +33,20 @@ func init() {
|
||||||
fwd_request(w, r, opts.DevProxy)
|
fwd_request(w, r, opts.DevProxy)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
api.Router().GET("/domains/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
opts := r.Context().Value("opts").(*config.Options)
|
||||||
|
|
||||||
|
if opts.DevProxy == "" {
|
||||||
|
if data, err := Asset("htdocs/dist/index.html"); err != nil {
|
||||||
|
fmt.Fprintf(w, "{\"errmsg\":%q}", err)
|
||||||
|
} else {
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r.URL.Path = "/"
|
||||||
|
fwd_request(w, r, opts.DevProxy)
|
||||||
|
}
|
||||||
|
})
|
||||||
api.Router().GET("/join", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
api.Router().GET("/join", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
opts := r.Context().Value("opts").(*config.Options)
|
opts := r.Context().Value("opts").(*config.Options)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,16 @@ type Storage interface {
|
||||||
DoMigration() error
|
DoMigration() error
|
||||||
Close() error
|
Close() error
|
||||||
|
|
||||||
|
GetDomains(u *happydns.User) (happydns.Domains, error)
|
||||||
|
GetDomain(u *happydns.User, id int) (*happydns.Domain, error)
|
||||||
|
GetDomainByDN(u *happydns.User, dn string) (*happydns.Domain, error)
|
||||||
|
DomainExists(dn string) bool
|
||||||
|
CreateDomain(u *happydns.User, z *happydns.Domain) error
|
||||||
|
UpdateDomain(z *happydns.Domain) error
|
||||||
|
UpdateDomainOwner(z *happydns.Domain, newOwner *happydns.User) error
|
||||||
|
DeleteDomain(z *happydns.Domain) error
|
||||||
|
ClearDomains() error
|
||||||
|
|
||||||
GetSession(id []byte) (*happydns.Session, error)
|
GetSession(id []byte) (*happydns.Session, error)
|
||||||
CreateSession(session *happydns.Session) error
|
CreateSession(session *happydns.Session) error
|
||||||
UpdateSession(session *happydns.Session) error
|
UpdateSession(session *happydns.Session) error
|
||||||
|
@ -22,14 +32,4 @@ type Storage interface {
|
||||||
UpdateUser(user *happydns.User) error
|
UpdateUser(user *happydns.User) error
|
||||||
DeleteUser(user *happydns.User) error
|
DeleteUser(user *happydns.User) error
|
||||||
ClearUsers() error
|
ClearUsers() error
|
||||||
|
|
||||||
GetZones(u *happydns.User) (happydns.Zones, error)
|
|
||||||
GetZone(u *happydns.User, id int) (*happydns.Zone, error)
|
|
||||||
GetZoneByDN(u *happydns.User, dn string) (*happydns.Zone, error)
|
|
||||||
ZoneExists(dn string) bool
|
|
||||||
CreateZone(u *happydns.User, z *happydns.Zone) error
|
|
||||||
UpdateZone(z *happydns.Zone) error
|
|
||||||
UpdateZoneOwner(z *happydns.Zone, newOwner *happydns.User) error
|
|
||||||
DeleteZone(z *happydns.Zone) error
|
|
||||||
ClearZones() error
|
|
||||||
}
|
}
|
||||||
|
|
127
storage/leveldb/domain.go
Normal file
127
storage/leveldb/domain.go
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.happydns.org/happydns/model"
|
||||||
|
|
||||||
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) GetDomains(u *happydns.User) (domains happydns.Domains, err error) {
|
||||||
|
iter := s.search("domain-")
|
||||||
|
defer iter.Release()
|
||||||
|
|
||||||
|
for iter.Next() {
|
||||||
|
var z happydns.Domain
|
||||||
|
|
||||||
|
err = decodeData(iter.Value(), &z)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if z.IdUser == u.Id {
|
||||||
|
domains = append(domains, &z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) GetDomain(u *happydns.User, id int) (z *happydns.Domain, err error) {
|
||||||
|
z = &happydns.Domain{}
|
||||||
|
err = s.get(fmt.Sprintf("domain-%d", id), &z)
|
||||||
|
|
||||||
|
if z.IdUser != u.Id {
|
||||||
|
z = nil
|
||||||
|
err = leveldb.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) GetDomainByDN(u *happydns.User, dn string) (*happydns.Domain, error) {
|
||||||
|
domains, err := s.GetDomains(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range domains {
|
||||||
|
if domain.DomainName == dn {
|
||||||
|
return domain, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, leveldb.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) DomainExists(dn string) bool {
|
||||||
|
iter := s.search("domain-")
|
||||||
|
defer iter.Release()
|
||||||
|
|
||||||
|
for iter.Next() {
|
||||||
|
var z happydns.Domain
|
||||||
|
|
||||||
|
err := decodeData(iter.Value(), &z)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if z.DomainName == dn {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) CreateDomain(u *happydns.User, z *happydns.Domain) error {
|
||||||
|
key, id, err := s.findInt63Key("domain-")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
z.Id = id
|
||||||
|
z.IdUser = u.Id
|
||||||
|
return s.put(key, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) UpdateDomain(z *happydns.Domain) error {
|
||||||
|
return s.put(fmt.Sprintf("domain-%d", z.Id), z)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) UpdateDomainOwner(z *happydns.Domain, newOwner *happydns.User) error {
|
||||||
|
z.IdUser = newOwner.Id
|
||||||
|
return s.put(fmt.Sprintf("domain-%d", z.Id), z)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) DeleteDomain(z *happydns.Domain) error {
|
||||||
|
return s.delete(fmt.Sprintf("domain-%d", z.Id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LevelDBStorage) ClearDomains() error {
|
||||||
|
tx, err := s.db.OpenTransaction()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
iter := tx.NewIterator(util.BytesPrefix([]byte("domain-")), nil)
|
||||||
|
defer iter.Release()
|
||||||
|
|
||||||
|
for iter.Next() {
|
||||||
|
err = tx.Delete(iter.Key(), nil)
|
||||||
|
if err != nil {
|
||||||
|
tx.Discard()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
tx.Discard()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,127 +0,0 @@
|
||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.happydns.org/happydns/model"
|
|
||||||
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) GetZones(u *happydns.User) (zones happydns.Zones, err error) {
|
|
||||||
iter := s.search("zone-")
|
|
||||||
defer iter.Release()
|
|
||||||
|
|
||||||
for iter.Next() {
|
|
||||||
var z happydns.Zone
|
|
||||||
|
|
||||||
err = decodeData(iter.Value(), &z)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if z.IdUser == u.Id {
|
|
||||||
zones = append(zones, &z)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) GetZone(u *happydns.User, id int) (z *happydns.Zone, err error) {
|
|
||||||
z = &happydns.Zone{}
|
|
||||||
err = s.get(fmt.Sprintf("zone-%d", id), &z)
|
|
||||||
|
|
||||||
if z.IdUser != u.Id {
|
|
||||||
z = nil
|
|
||||||
err = leveldb.ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) GetZoneByDN(u *happydns.User, dn string) (*happydns.Zone, error) {
|
|
||||||
zones, err := s.GetZones(u)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, zone := range zones {
|
|
||||||
if zone.DomainName == dn {
|
|
||||||
return zone, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, leveldb.ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) ZoneExists(dn string) bool {
|
|
||||||
iter := s.search("zone-")
|
|
||||||
defer iter.Release()
|
|
||||||
|
|
||||||
for iter.Next() {
|
|
||||||
var z happydns.Zone
|
|
||||||
|
|
||||||
err := decodeData(iter.Value(), &z)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if z.DomainName == dn {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) CreateZone(u *happydns.User, z *happydns.Zone) error {
|
|
||||||
key, id, err := s.findInt63Key("zone-")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
z.Id = id
|
|
||||||
z.IdUser = u.Id
|
|
||||||
return s.put(key, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) UpdateZone(z *happydns.Zone) error {
|
|
||||||
return s.put(fmt.Sprintf("zone-%d", z.Id), z)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) UpdateZoneOwner(z *happydns.Zone, newOwner *happydns.User) error {
|
|
||||||
z.IdUser = newOwner.Id
|
|
||||||
return s.put(fmt.Sprintf("zone-%d", z.Id), z)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) DeleteZone(z *happydns.Zone) error {
|
|
||||||
return s.delete(fmt.Sprintf("zone-%d", z.Id))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStorage) ClearZones() error {
|
|
||||||
tx, err := s.db.OpenTransaction()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
iter := tx.NewIterator(util.BytesPrefix([]byte("zone-")), nil)
|
|
||||||
defer iter.Release()
|
|
||||||
|
|
||||||
for iter.Next() {
|
|
||||||
err = tx.Delete(iter.Key(), nil)
|
|
||||||
if err != nil {
|
|
||||||
tx.Discard()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tx.Commit()
|
|
||||||
if err != nil {
|
|
||||||
tx.Discard()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
81
storage/mysql/domain.go
Normal file
81
storage/mysql/domain.go
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.happydns.org/happydns/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *MySQLStorage) GetDomains(u *happydns.User) (domains happydns.Domains, err error) {
|
||||||
|
if rows, errr := s.db.Query("SELECT id_domain, id_user, id_source, domain FROM domains WHERE id_user = ?", u.Id); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var z happydns.Domain
|
||||||
|
if err = rows.Scan(&z.Id, &z.IdUser, &z.IdSource, &z.DomainName); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domains = append(domains, &z)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) GetDomain(u *happydns.User, id int) (z *happydns.Domain, err error) {
|
||||||
|
z = &happydns.Domain{}
|
||||||
|
err = s.db.QueryRow("SELECT id_domain, id_user, id_source, domain FROM domains WHERE id_domain=? AND id_user=?", id, u.Id).Scan(&z.Id, &z.IdUser, &z.IdSource, &z.DomainName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) GetDomainByDN(u *happydns.User, dn string) (z *happydns.Domain, err error) {
|
||||||
|
z = &happydns.Domain{}
|
||||||
|
err = s.db.QueryRow("SELECT id_domain, id_user, id_source, domain FROM domains WHERE domain=? AND id_user=?", dn, u.Id).Scan(&z.Id, &z.IdUser, &z.IdSource, &z.DomainName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) DomainExists(dn string) bool {
|
||||||
|
var z int
|
||||||
|
err := s.db.QueryRow("SELECT 1 FROM domains WHERE domain=?", dn).Scan(&z)
|
||||||
|
return err == nil && z == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) CreateDomain(u *happydns.User, src happydns.SourceType, z *happydns.Domain) error {
|
||||||
|
if res, err := s.db.Exec("INSERT INTO domains (id_user, id_source, domain) VALUES (?, ?, ?)", u.Id, src.Id, z.DomainName); err != nil {
|
||||||
|
return err
|
||||||
|
} else if z.Id, err = res.LastInsertId(); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) UpdateDomain(z *happydns.Domain) error {
|
||||||
|
if _, err := s.db.Exec("UPDATE domains SET id_source = ?, domain = ? WHERE id_domain = ?", z.IdSource, z.DomainName, z.Id); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) UpdateDomainOwner(z *happydns.Domain, newOwner *happydns.User) error {
|
||||||
|
if _, err := s.db.Exec("UPDATE domains SET id_user = ? WHERE id_domain = ?", newOwner.Id, z.Id); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
z.IdUser = newOwner.Id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) DeleteDomain(z *happydns.Domain) error {
|
||||||
|
_, err := s.db.Exec("DELETE FROM domains WHERE id_domain = ?", z.Id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStorage) ClearDomains() error {
|
||||||
|
_, err := s.db.Exec("DELETE FROM domains")
|
||||||
|
return err
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
package database // import "happydns.org/database"
|
package database // import "happydns.org/database"
|
||||||
|
|
||||||
const schemaVersion = 2
|
const schemaVersion = 3
|
||||||
|
|
||||||
var schemaRevisions = map[uint16]string{
|
var schemaRevisions = map[uint16]string{
|
||||||
1: `CREATE TABLE schema_version (
|
1: `CREATE TABLE schema_version (
|
||||||
|
@ -50,5 +50,18 @@ ALTER TABLE user_sessions
|
||||||
|
|
||||||
ALTER TABLE zones
|
ALTER TABLE zones
|
||||||
CHANGE id_user id_user BIGINT NOT NULL;
|
CHANGE id_user id_user BIGINT NOT NULL;
|
||||||
|
`,
|
||||||
|
3: `ALTER TABLE zones
|
||||||
|
DROP COLUMN server;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN key_name;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN key_algo;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN key_blob;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN storage_facility;
|
||||||
|
|
||||||
|
RENAME TABLE zones TO domains;
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
12
storage/mysql/schemas/003.sql
Normal file
12
storage/mysql/schemas/003.sql
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN server;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN key_name;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN key_algo;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN key_blob;
|
||||||
|
ALTER TABLE zones
|
||||||
|
DROP COLUMN storage_facility;
|
||||||
|
|
||||||
|
RENAME TABLE zones TO domains;
|
|
@ -1,81 +0,0 @@
|
||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.happydns.org/happydns/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *MySQLStorage) GetZones(u *happydns.User) (zones happydns.Zones, err error) {
|
|
||||||
if rows, errr := s.db.Query("SELECT id_zone, id_user, domain, server, key_name, key_algo, key_blob, storage_facility FROM zones WHERE id_user = ?", u.Id); errr != nil {
|
|
||||||
return nil, errr
|
|
||||||
} else {
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var z happydns.Zone
|
|
||||||
if err = rows.Scan(&z.Id, &z.IdUser, &z.DomainName, &z.Server, &z.KeyName, &z.KeyAlgo, &z.KeyBlob, &z.StorageFacility); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
zones = append(zones, &z)
|
|
||||||
}
|
|
||||||
if err = rows.Err(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) GetZone(u *happydns.User, id int) (z *happydns.Zone, err error) {
|
|
||||||
z = &happydns.Zone{}
|
|
||||||
err = s.db.QueryRow("SELECT id_zone, id_user, domain, server, key_name, key_algo, key_blob, storage_facility FROM zones WHERE id_zone=? AND id_user=?", id, u.Id).Scan(&z.Id, &z.IdUser, &z.DomainName, &z.Server, &z.KeyName, &z.KeyAlgo, &z.KeyBlob, &z.StorageFacility)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) GetZoneByDN(u *happydns.User, dn string) (z *happydns.Zone, err error) {
|
|
||||||
z = &happydns.Zone{}
|
|
||||||
err = s.db.QueryRow("SELECT id_zone, id_user, domain, server, key_name, key_algo, key_blob, storage_facility FROM zones WHERE domain=? AND id_user=?", dn, u.Id).Scan(&z.Id, &z.IdUser, &z.DomainName, &z.Server, &z.KeyName, &z.KeyAlgo, &z.KeyBlob, &z.StorageFacility)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) ZoneExists(dn string) bool {
|
|
||||||
var z int
|
|
||||||
err := s.db.QueryRow("SELECT 1 FROM zones WHERE domain=?", dn).Scan(&z)
|
|
||||||
return err == nil && z == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) CreateZone(u *happydns.User, z *happydns.Zone) error {
|
|
||||||
if res, err := s.db.Exec("INSERT INTO zones (id_user, domain, server, key_name, key_blob, storage_facility) VALUES (?, ?, ?, ?, ?, ?)", u.Id, z.DomainName, z.Server, z.KeyName, z.KeyBlob, z.StorageFacility); err != nil {
|
|
||||||
return err
|
|
||||||
} else if z.Id, err = res.LastInsertId(); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) UpdateZone(z *happydns.Zone) error {
|
|
||||||
if _, err := s.db.Exec("UPDATE zones SET domain = ?, key_name = ?, key_algo = ?, key_blob = ?, storage_facility = ? WHERE id_zone = ?", z.DomainName, z.KeyName, z.KeyAlgo, z.KeyBlob, z.StorageFacility, z.Id); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) UpdateZoneOwner(z *happydns.Zone, newOwner *happydns.User) error {
|
|
||||||
if _, err := s.db.Exec("UPDATE zones SET id_user = ? WHERE id_zone = ?", newOwner.Id, z.Id); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
z.IdUser = newOwner.Id
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) DeleteZone(z *happydns.Zone) error {
|
|
||||||
_, err := s.db.Exec("DELETE FROM zones WHERE id_zone = ?", z.Id)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MySQLStorage) ClearZones() error {
|
|
||||||
_, err := s.db.Exec("DELETE FROM zones")
|
|
||||||
return err
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user