From 285475f3529d2e5a70ab89f96517ba6223f7b6dd Mon Sep 17 00:00:00 2001 From: Andrew Snyder Date: Sun, 21 Aug 2022 01:23:42 -0400 Subject: [PATCH] each google subdomain can have(?) or has it's own email and password --- internal/handler/handler.go | 32 ++++++++++++++++++++++ internal/provider/google/google_handler.go | 8 ++++-- internal/settings/settings.go | 28 +++++++++++++++++-- internal/utils/settings.go | 21 +++++++++++++- 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/internal/handler/handler.go b/internal/handler/handler.go index b443703e..eb1ceae8 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -109,6 +109,38 @@ func (handler *Handler) updateDNS(domain *settings.Domain, ip string) error { } } } + for _, designated := range domain.DelegatedSubDomains { + + hostname := designated.DomainName + "." + domain.DomainName + + lastIP, err := utils.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType) + if err != nil && (errors.Is(err, errEmptyResult) || errors.Is(err, errEmptyDomain)) { + log.Errorf("Failed to resolve DNS for domain: %s, error: %s", hostname, err) + continue + } + + //check against the current known IP, if no change, skip update + if ip == lastIP { + log.Infof("IP is the same as cached one (%s). Skip update.", ip) + } else { + + handler.Configuration.Email = designated.Email + handler.Configuration.Password = designated.Password + if err := handler.dnsProvider.UpdateIP(domain.DomainName, designated.DomainName, ip); err != nil { + return err + } + + successMessage := fmt.Sprintf("%s.%s", designated.DomainName, domain.DomainName) + handler.notificationManager.Send(successMessage, ip) + + // execute webhook when it is enabled + if handler.Configuration.Webhook.Enabled { + if err := lib.GetWebhook(handler.Configuration).Execute(hostname, ip); err != nil { + return err + } + } + } + } return nil } diff --git a/internal/provider/google/google_handler.go b/internal/provider/google/google_handler.go index ca020eac..3df8b4e0 100644 --- a/internal/provider/google/google_handler.go +++ b/internal/provider/google/google_handler.go @@ -34,12 +34,13 @@ func (provider *DNSProvider) UpdateIP(domainName, subdomainName, ip string) erro // updateIP update subdomain with current IP. func (provider *DNSProvider) updateIP(domain, subDomain, currentIP string) error { client := utils.GetHTTPClient(provider.configuration) - resp, err := client.Get(fmt.Sprintf(URL, + request := fmt.Sprintf(URL, provider.configuration.Email, provider.configuration.Password, subDomain, domain, - currentIP)) + currentIP) + resp, err := client.Get(request) if err != nil { // handle error @@ -69,6 +70,9 @@ func (provider *DNSProvider) updateIP(domain, subDomain, currentIP string) error log.Infof("Update IP success: %s", string(body)) } else if strings.Contains(string(body), "nochg") { log.Infof("IP not changed: %s", string(body)) + } else { + // google api can return StatusOK even if it fails + log.Errorf("Update IP failed: %s", string(body)) } return nil diff --git a/internal/settings/settings.go b/internal/settings/settings.go index 08caeb40..6805b92a 100644 --- a/internal/settings/settings.go +++ b/internal/settings/settings.go @@ -21,10 +21,18 @@ const ( extYML = "yml" ) +// DelagatedSubDomain +type DelegatedSubDomain struct { + DomainName string `json:"domain_name" yaml:"domain_name"` + Email string `json:"email" yaml:"email"` + Password string `json:"password" yaml:"password"` +} + // Domain struct. type Domain struct { - DomainName string `json:"domain_name" yaml:"domain_name"` - SubDomains []string `json:"sub_domains" yaml:"sub_domains"` + DomainName string `json:"domain_name" yaml:"domain_name"` + SubDomains []string `json:"sub_domains" yaml:"sub_domains"` + DelegatedSubDomains []DelegatedSubDomain `json:"delegated_sub_domains" yaml:"delegated_sub_domains"` } // SlackNotify struct for Slack notification. @@ -170,7 +178,21 @@ func loadSecretsFromFile(settings *Settings) error { settings.PasswordFile, settings.Password, ); err != nil { - return fmt.Errorf("failed to load password from file: %w", err) + any := false + for _, domain := range settings.Domains { + for _, sub_domain := range domain.DelegatedSubDomains { + if len(sub_domain.Password) == 0 { + name := fmt.Sprint("%s:%s", domain.DomainName, sub_domain.DomainName) + return fmt.Errorf("failed to find delegated sub domain password: %w", errors.New(name)) + } else { + any = true + } + + } + } + if !any { + return fmt.Errorf("failed to load password from file: %w", err) + } } if settings.LoginToken, err = readSecretFromFile( diff --git a/internal/utils/settings.go b/internal/utils/settings.go index 643d7995..c1ea4a11 100644 --- a/internal/utils/settings.go +++ b/internal/utils/settings.go @@ -43,7 +43,26 @@ func CheckSettings(config *settings.Settings) error { return errors.New("login token cannot be empty") } case GOOGLE: - fallthrough + any := false + if config.Email == "" { + for _, domain := range config.Domains { + for _, sub_domain := range domain.DelegatedSubDomains { + if len(sub_domain.Email) == 0 { + name := fmt.Sprint("failed to find delegated sub domain email: %s:%s", domain.DomainName, sub_domain.DomainName) + return errors.New(name) + } else { + any = true + } + + } + } + if !any { + return errors.New("email cannot be empty") + } + } + if config.Password == "" && any == false { + return errors.New("password cannot be empty") + } case NOIP: if config.Email == "" { return errors.New("email cannot be empty")