2020-06-08 23:25:15 +00:00
|
|
|
// Copyright or © or Copr. happyDNS (2020)
|
|
|
|
//
|
|
|
|
// contact@happydns.org
|
|
|
|
//
|
|
|
|
// This software is a computer program whose purpose is to provide a modern
|
|
|
|
// interface to interact with DNS systems.
|
|
|
|
//
|
|
|
|
// This software is governed by the CeCILL license under French law and abiding
|
|
|
|
// by the rules of distribution of free software. You can use, modify and/or
|
|
|
|
// redistribute the software under the terms of the CeCILL license as
|
|
|
|
// circulated by CEA, CNRS and INRIA at the following URL
|
|
|
|
// "http://www.cecill.info".
|
|
|
|
//
|
|
|
|
// As a counterpart to the access to the source code and rights to copy, modify
|
|
|
|
// and redistribute granted by the license, users are provided only with a
|
|
|
|
// limited warranty and the software's author, the holder of the economic
|
|
|
|
// rights, and the successive licensors have only limited liability.
|
|
|
|
//
|
|
|
|
// In this respect, the user's attention is drawn to the risks associated with
|
|
|
|
// loading, using, modifying and/or developing or reproducing the software by
|
|
|
|
// the user in light of its specific status of free software, that may mean
|
|
|
|
// that it is complicated to manipulate, and that also therefore means that it
|
|
|
|
// is reserved for developers and experienced professionals having in-depth
|
|
|
|
// computer knowledge. Users are therefore encouraged to load and test the
|
|
|
|
// software's suitability as regards their requirements in conditions enabling
|
|
|
|
// the security of their systems and/or data to be ensured and, more generally,
|
|
|
|
// to use and operate it in the same conditions as regards security.
|
|
|
|
//
|
|
|
|
// The fact that you are presently reading this means that you have had
|
|
|
|
// knowledge of the CeCILL license and that you accept its terms.
|
|
|
|
|
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2020-09-29 21:07:56 +00:00
|
|
|
"encoding/hex"
|
2020-06-10 23:18:33 +00:00
|
|
|
"fmt"
|
2021-05-05 01:48:16 +00:00
|
|
|
"log"
|
2020-06-08 23:25:15 +00:00
|
|
|
"net/http"
|
|
|
|
"strconv"
|
2020-06-20 21:45:02 +00:00
|
|
|
"strings"
|
2020-06-24 15:33:34 +00:00
|
|
|
"time"
|
2020-06-08 23:25:15 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
"github.com/gin-gonic/gin"
|
2020-06-25 21:47:50 +00:00
|
|
|
"github.com/miekg/dns"
|
2020-06-08 23:25:15 +00:00
|
|
|
|
|
|
|
"git.happydns.org/happydns/config"
|
|
|
|
"git.happydns.org/happydns/model"
|
|
|
|
"git.happydns.org/happydns/services"
|
2020-10-10 16:44:17 +00:00
|
|
|
"git.happydns.org/happydns/services/abstract"
|
2020-06-25 21:47:50 +00:00
|
|
|
"git.happydns.org/happydns/sources"
|
2020-06-08 23:25:15 +00:00
|
|
|
"git.happydns.org/happydns/storage"
|
|
|
|
)
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func declareZonesRoutes(cfg *config.Options, router *gin.RouterGroup) {
|
|
|
|
router.POST("/import_zone", importZone)
|
|
|
|
router.POST("/diff_zones/:zoneid1/:zoneid2", diffZones)
|
2020-06-25 21:47:50 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
apiZonesRoutes := router.Group("/zone/:zoneid")
|
|
|
|
apiZonesRoutes.Use(ZoneHandler)
|
2020-06-08 23:25:15 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
apiZonesRoutes.POST("/view", viewZone)
|
|
|
|
apiZonesRoutes.POST("/apply_changes", applyZone)
|
|
|
|
|
|
|
|
apiZonesRoutes.GET("", GetZone)
|
|
|
|
apiZonesRoutes.PATCH("", UpdateZoneService)
|
|
|
|
|
|
|
|
apiZonesSubdomainRoutes := apiZonesRoutes.Group("/:subdomain")
|
|
|
|
apiZonesSubdomainRoutes.Use(subdomainHandler)
|
|
|
|
apiZonesSubdomainRoutes.GET("", getZoneSubdomain)
|
|
|
|
apiZonesSubdomainRoutes.POST("/services", addZoneService)
|
|
|
|
|
|
|
|
declareServiceSettingsRoutes(cfg, apiZonesSubdomainRoutes)
|
|
|
|
|
|
|
|
apiZonesSubdomainServiceIdRoutes := apiZonesSubdomainRoutes.Group("/services/:serviceid")
|
|
|
|
apiZonesSubdomainServiceIdRoutes.Use(serviceIdHandler)
|
|
|
|
apiZonesSubdomainServiceIdRoutes.GET("", getZoneService)
|
|
|
|
apiZonesSubdomainServiceIdRoutes.DELETE("", deleteZoneService)
|
|
|
|
apiZonesSubdomainServiceIdRoutes.GET("/records", getServiceRecords)
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func loadZoneFromId(domain *happydns.Domain, id string) (*happydns.Zone, int, error) {
|
|
|
|
zoneid, err := strconv.ParseInt(id, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return nil, http.StatusBadRequest, fmt.Errorf("Invalid zoneid: %q", id)
|
|
|
|
}
|
2020-06-08 23:25:15 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
// Check that the zoneid exists in the domain history
|
|
|
|
if !domain.HasZone(zoneid) {
|
|
|
|
return nil, http.StatusNotFound, fmt.Errorf("Zone not found: %q", id)
|
|
|
|
}
|
2020-06-08 23:25:15 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
zone, err := storage.MainStore.GetZone(zoneid)
|
|
|
|
if err != nil {
|
|
|
|
return nil, http.StatusNotFound, fmt.Errorf("Zone not found: %q", id)
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
2021-05-05 01:48:16 +00:00
|
|
|
|
|
|
|
return zone, http.StatusOK, nil
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func ZoneHandler(c *gin.Context) {
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
|
|
|
|
zone, statuscode, err := loadZoneFromId(domain, c.Param("zoneid"))
|
|
|
|
if err != nil {
|
|
|
|
c.AbortWithStatusJSON(statuscode, gin.H{"errmsg": err.Error()})
|
|
|
|
return
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
2021-05-05 01:48:16 +00:00
|
|
|
|
|
|
|
c.Set("zone", zone)
|
|
|
|
|
|
|
|
c.Next()
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func GetZone(c *gin.Context) {
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, zone)
|
|
|
|
}
|
|
|
|
|
|
|
|
func subdomainHandler(c *gin.Context) {
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
|
|
|
|
subdomain := strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(c.Param("subdomain"), "."+domain.DomainName), "@"), domain.DomainName)
|
|
|
|
|
|
|
|
c.Set("subdomain", subdomain)
|
|
|
|
|
|
|
|
c.Next()
|
|
|
|
}
|
|
|
|
|
|
|
|
func getZoneSubdomain(c *gin.Context) {
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
subdomain := c.MustGet("subdomain").(string)
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{"services": zone.Services[subdomain]})
|
2020-06-14 20:58:28 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func addZoneService(c *gin.Context) {
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
subdomain := c.MustGet("subdomain").(string)
|
|
|
|
|
2020-06-20 21:45:02 +00:00
|
|
|
usc := &happydns.ServiceCombined{}
|
2021-05-05 01:48:16 +00:00
|
|
|
err := c.ShouldBindJSON(&usc)
|
2020-06-20 21:45:02 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s sends invalid service JSON: %w", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Something is wrong in received data: %w", err)})
|
|
|
|
return
|
2020-06-20 21:45:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if usc.Service == nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Unable to parse the given service."})
|
|
|
|
return
|
2020-06-20 21:45:02 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = zone.AppendService(subdomain, domain.DomainName, usc)
|
2020-10-10 16:47:41 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Unable to add service: %w", err)})
|
|
|
|
return
|
2020-06-20 21:45:02 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = storage.MainStore.UpdateZone(zone)
|
2020-06-20 21:45:02 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s: Unable to UpdateZone in updateZoneService: %w", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are currently unable to update your zone. Please retry later."})
|
|
|
|
return
|
2020-06-20 21:45:02 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, zone)
|
2020-06-20 21:45:02 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func serviceIdHandler(c *gin.Context) {
|
|
|
|
serviceid, err := hex.DecodeString(c.Param("serviceid"))
|
2020-06-14 20:58:28 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Bad service identifier: %w", err)})
|
|
|
|
return
|
2020-06-14 20:58:28 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.Set("serviceid", serviceid)
|
|
|
|
|
|
|
|
c.Next()
|
2020-06-14 20:58:28 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func getZoneService(c *gin.Context) {
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
serviceid := c.MustGet("serviceid").([]byte)
|
|
|
|
subdomain := c.MustGet("subdomain").(string)
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, zone.FindSubdomainService(subdomain, serviceid))
|
|
|
|
}
|
|
|
|
|
|
|
|
func importZone(c *gin.Context) {
|
|
|
|
user := c.MustGet("LoggedUser").(*happydns.User)
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
|
2021-05-21 11:08:18 +00:00
|
|
|
provider, err := storage.MainStore.GetProvider(user, domain.IdProvider)
|
2020-06-08 23:25:15 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": fmt.Sprintf("Unable to find your provider: %w", err)})
|
|
|
|
return
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-21 11:08:18 +00:00
|
|
|
zone, err := provider.ImportZone(domain)
|
2020-06-08 23:25:15 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
|
|
|
|
return
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
services, defaultTTL, err := svcs.AnalyzeZone(domain.DomainName, zone)
|
2020-06-08 23:25:15 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
|
|
|
|
return
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
myZone := &happydns.Zone{
|
2020-06-24 15:33:34 +00:00
|
|
|
ZoneMeta: happydns.ZoneMeta{
|
2021-05-05 01:48:16 +00:00
|
|
|
IdAuthor: domain.IdUser,
|
2020-06-24 15:33:34 +00:00
|
|
|
DefaultTTL: defaultTTL,
|
|
|
|
LastModified: time.Now(),
|
|
|
|
},
|
|
|
|
Services: services,
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
2020-12-20 11:01:33 +00:00
|
|
|
// Create history zone
|
2020-06-08 23:25:15 +00:00
|
|
|
err = storage.MainStore.CreateZone(myZone)
|
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s: unable to CreateZone in importZone: %w\n", c.ClientIP(), err.Error())
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are unable to create your zone."})
|
|
|
|
return
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
2021-05-05 01:48:16 +00:00
|
|
|
domain.ZoneHistory = append(
|
|
|
|
[]int64{myZone.Id}, domain.ZoneHistory...)
|
2020-06-08 23:25:15 +00:00
|
|
|
|
2020-12-20 11:01:33 +00:00
|
|
|
// Create wip zone
|
|
|
|
err = storage.MainStore.CreateZone(myZone)
|
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s: unable to CreateZone2 in importZone: %w\n", c.ClientIP(), err.Error())
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are unable to create your zone."})
|
|
|
|
return
|
2020-12-20 11:01:33 +00:00
|
|
|
}
|
2021-05-05 01:48:16 +00:00
|
|
|
domain.ZoneHistory = append(
|
|
|
|
[]int64{myZone.Id}, domain.ZoneHistory...)
|
2020-06-08 23:25:15 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = storage.MainStore.UpdateDomain(domain)
|
2020-06-08 23:25:15 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s: unable to UpdateDomain in importZone: %w\n", c.ClientIP(), err.Error())
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are unable to create your zone."})
|
|
|
|
return
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, &myZone.ZoneMeta)
|
2020-06-08 23:25:15 +00:00
|
|
|
}
|
2020-06-10 23:18:33 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func loadRecordsFromZoneId(user *happydns.User, domain *happydns.Domain, id string) ([]dns.RR, int, error) {
|
|
|
|
if id == "@" {
|
2021-05-21 11:08:18 +00:00
|
|
|
source, err := storage.MainStore.GetSource(user, domain.IdProvider)
|
2020-06-25 21:47:50 +00:00
|
|
|
if err != nil {
|
2021-05-21 11:08:18 +00:00
|
|
|
return nil, http.StatusNotFound, fmt.Errorf("Unable to find the given source: %q for %q", domain.IdProvider, domain.DomainName)
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
rrs, err := source.ImportZone(domain)
|
2020-06-25 21:47:50 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
// statuscode should not be significant if err is nil
|
|
|
|
return rrs, http.StatusBadRequest, err
|
|
|
|
} else {
|
|
|
|
zone, statuscode, err := loadZoneFromId(domain, id)
|
2020-06-25 21:47:50 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
return nil, statuscode, err
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
2021-05-05 01:48:16 +00:00
|
|
|
|
|
|
|
return zone.GenerateRRs(domain.DomainName), http.StatusOK, err
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
2021-05-05 01:48:16 +00:00
|
|
|
}
|
2020-06-25 21:47:50 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func diffZones(c *gin.Context) {
|
|
|
|
user := c.MustGet("LoggedUser").(*happydns.User)
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
|
|
|
|
zone1, statuscode, err := loadRecordsFromZoneId(user, domain, c.Param("zoneid1"))
|
|
|
|
if err != nil {
|
|
|
|
c.AbortWithStatusJSON(statuscode, gin.H{"errmsg": err.Error()})
|
|
|
|
return
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
zone2, statuscode, err := loadRecordsFromZoneId(user, domain, c.Param("zoneid2"))
|
|
|
|
if err != nil {
|
|
|
|
c.AbortWithStatusJSON(statuscode, gin.H{"errmsg": err.Error()})
|
|
|
|
return
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2020-06-27 14:18:50 +00:00
|
|
|
toAdd, toDel := sources.DiffZones(zone1, zone2, true)
|
2020-06-25 21:47:50 +00:00
|
|
|
|
|
|
|
var rrAdd []string
|
|
|
|
for _, rr := range toAdd {
|
|
|
|
rrAdd = append(rrAdd, rr.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
var rrDel []string
|
|
|
|
for _, rr := range toDel {
|
|
|
|
rrDel = append(rrDel, rr.String())
|
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
"toAdd": rrAdd,
|
|
|
|
"toDel": rrDel,
|
|
|
|
})
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func applyZone(c *gin.Context) {
|
|
|
|
user := c.MustGet("LoggedUser").(*happydns.User)
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
|
2021-05-21 11:08:18 +00:00
|
|
|
source, err := storage.MainStore.GetSource(user, domain.IdProvider)
|
2020-06-25 21:47:50 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": fmt.Sprintf("Unable to find your provider: %w", err)})
|
|
|
|
return
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
newSOA, err := sources.ApplyZone(source, domain, zone.GenerateRRs(domain.DomainName), true)
|
2020-06-25 21:47:50 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s: unable to ApplyZone in applyZone", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to create the diff. Please retry later or contact an administrator."})
|
|
|
|
return
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update serial
|
|
|
|
if newSOA != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
for _, svc := range zone.Services[""] {
|
2020-10-10 16:44:17 +00:00
|
|
|
if origin, ok := svc.Service.(*abstract.Origin); ok {
|
2020-06-25 21:47:50 +00:00
|
|
|
origin.Serial = newSOA.Serial
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new zone in history for futher updates
|
2021-05-05 01:48:16 +00:00
|
|
|
newZone := zone.DerivateNew()
|
2020-06-25 21:47:50 +00:00
|
|
|
//newZone.IdAuthor = //TODO get current user id
|
|
|
|
err = storage.MainStore.CreateZone(newZone)
|
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s was unable to CreateZone", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are unable to create the zone now."})
|
|
|
|
return
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
domain.ZoneHistory = append(
|
|
|
|
[]int64{newZone.Id}, domain.ZoneHistory...)
|
2020-06-25 21:47:50 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = storage.MainStore.UpdateDomain(domain)
|
2020-06-25 21:47:50 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s was unable to UpdateDomain", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are unable to create the zone now."})
|
|
|
|
return
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Commit changes in previous zone
|
|
|
|
now := time.Now()
|
|
|
|
// zone.ZoneMeta.IdAuthor = // TODO get current user id
|
2021-05-05 01:48:16 +00:00
|
|
|
zone.ZoneMeta.Published = &now
|
2020-06-25 21:47:50 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
zone.LastModified = time.Now()
|
2020-06-25 21:47:50 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = storage.MainStore.UpdateZone(zone)
|
2020-06-25 21:47:50 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s was unable to UpdateZone", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are unable to create the zone now."})
|
|
|
|
return
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, newZone.ZoneMeta)
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func viewZone(c *gin.Context) {
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
|
2020-06-25 21:47:50 +00:00
|
|
|
var ret string
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
for _, rr := range zone.GenerateRRs(domain.DomainName) {
|
2020-06-25 21:47:50 +00:00
|
|
|
ret += rr.String() + "\n"
|
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, ret)
|
2020-06-25 21:47:50 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func UpdateZoneService(c *gin.Context) {
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
|
2020-06-10 23:18:33 +00:00
|
|
|
usc := &happydns.ServiceCombined{}
|
2021-05-05 01:48:16 +00:00
|
|
|
err := c.ShouldBindJSON(&usc)
|
2020-06-10 23:18:33 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s sends invalid domain JSON: %w", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Something is wrong in received data: %w", err)})
|
|
|
|
return
|
2020-06-10 23:18:33 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = zone.EraseService(usc.Domain, domain.DomainName, usc.Id, usc)
|
2020-06-14 20:58:28 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Unable to delete service: %w", err)})
|
|
|
|
return
|
2020-06-14 20:58:28 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
zone.LastModified = time.Now()
|
2020-06-24 15:33:34 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = storage.MainStore.UpdateZone(zone)
|
2020-06-14 20:58:28 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s: Unable to UpdateZone in updateZoneService: %w", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are currently unable to update your zone. Please retry later."})
|
|
|
|
return
|
2020-06-14 20:58:28 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, zone)
|
2020-06-14 20:58:28 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func deleteZoneService(c *gin.Context) {
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
serviceid := c.MustGet("serviceid").([]byte)
|
|
|
|
subdomain := c.MustGet("subdomain").(string)
|
2021-01-09 18:56:20 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err := zone.EraseService(subdomain, domain.DomainName, serviceid, nil)
|
2020-06-10 23:18:33 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Unable to delete service: %w", err)})
|
|
|
|
return
|
2020-06-10 23:18:33 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
zone.LastModified = time.Now()
|
2020-06-24 15:33:34 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
err = storage.MainStore.UpdateZone(zone)
|
2020-06-10 23:18:33 +00:00
|
|
|
if err != nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
log.Printf("%s: Unable to UpdateZone in deleteZoneService: %w", c.ClientIP(), err)
|
|
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are currently unable to update your zone. Please retry later."})
|
|
|
|
return
|
2020-06-10 23:18:33 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, zone)
|
2020-06-10 23:18:33 +00:00
|
|
|
}
|
2020-09-29 21:34:28 +00:00
|
|
|
|
2020-08-21 11:52:59 +00:00
|
|
|
type serviceRecord struct {
|
|
|
|
String string `json:"string"`
|
|
|
|
Fields *dns.RR `json:"fields,omitempty"`
|
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
func getServiceRecords(c *gin.Context) {
|
|
|
|
domain := c.MustGet("domain").(*happydns.Domain)
|
|
|
|
zone := c.MustGet("zone").(*happydns.Zone)
|
|
|
|
serviceid := c.MustGet("serviceid").([]byte)
|
|
|
|
subdomain := c.MustGet("subdomain").(string)
|
2021-01-22 13:49:39 +00:00
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
svc := zone.FindSubdomainService(subdomain, serviceid)
|
2020-09-29 21:34:28 +00:00
|
|
|
if svc == nil {
|
2021-05-05 01:48:16 +00:00
|
|
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Service not found."})
|
|
|
|
return
|
2020-09-29 21:34:28 +00:00
|
|
|
}
|
|
|
|
|
2020-08-21 11:52:59 +00:00
|
|
|
var ret []serviceRecord
|
2021-05-05 01:48:16 +00:00
|
|
|
for _, rr := range svc.GenRRs(subdomain, 3600, domain.DomainName) {
|
2020-08-21 11:52:59 +00:00
|
|
|
ret = append(ret, serviceRecord{
|
|
|
|
String: rr.String(),
|
|
|
|
Fields: &rr,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-05-05 01:48:16 +00:00
|
|
|
c.JSON(http.StatusOK, ret)
|
2020-09-29 21:34:28 +00:00
|
|
|
}
|