568452846a
POST /accounts now accepts secret as a provider-specific JSON object instead of an opaque string, and validates credentials via provider.Provider.Validate before persisting — invalid credentials get a generic 400 without ever reaching Store.CreateAccount or echoing the secret back. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
93 lines
2.7 KiB
Go
93 lines
2.7 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/vasyakrg/dns-autoresolver/internal/store"
|
|
"github.com/vasyakrg/dns-autoresolver/internal/store/dto"
|
|
)
|
|
|
|
// accountRequest.Secret is a provider-specific JSON object (e.g. Selectel's
|
|
// service-user credentials) rather than an opaque string — it is passed
|
|
// through as raw bytes to Validate/Encrypt, never parsed here.
|
|
type accountRequest struct {
|
|
Provider string `json:"provider"`
|
|
Secret json.RawMessage `json:"secret"`
|
|
Comment string `json:"comment"`
|
|
}
|
|
|
|
// accountResponse deliberately excludes the secret (plaintext or encrypted).
|
|
type accountResponse struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
Comment string `json:"comment"`
|
|
}
|
|
|
|
func toAccountResponse(a store.Account) accountResponse {
|
|
return accountResponse{ID: a.ID.String(), Provider: a.Provider, Comment: a.Comment}
|
|
}
|
|
|
|
type templateRequest struct {
|
|
Name string `json:"name"`
|
|
Records []dto.RecordDTO `json:"records"`
|
|
}
|
|
|
|
type templateResponse struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Records []dto.RecordDTO `json:"records"`
|
|
Version int32 `json:"version"`
|
|
}
|
|
|
|
func toTemplateResponse(t store.Template) templateResponse {
|
|
return templateResponse{ID: t.ID.String(), Name: t.Name, Records: t.Doc.Records, Version: t.Version}
|
|
}
|
|
|
|
type domainRequest struct {
|
|
ProviderAccountID string `json:"providerAccountId"`
|
|
ZoneName string `json:"zoneName"`
|
|
ZoneID string `json:"zoneId"`
|
|
TemplateID *string `json:"templateId,omitempty"`
|
|
}
|
|
|
|
// updateDomainTemplateRequest is the PATCH .../domains/{did} body used to
|
|
// bind (or clear, when templateId is null/omitted) a domain's DNS template.
|
|
type updateDomainTemplateRequest struct {
|
|
TemplateID *string `json:"templateId"`
|
|
}
|
|
|
|
type domainResponse struct {
|
|
ID string `json:"id"`
|
|
ProviderAccountID string `json:"providerAccountId"`
|
|
ZoneName string `json:"zoneName"`
|
|
ZoneID string `json:"zoneId"`
|
|
TemplateID *string `json:"templateId,omitempty"`
|
|
LastCheckStatus string `json:"lastCheckStatus"`
|
|
}
|
|
|
|
func toDomainResponse(d store.Domain) domainResponse {
|
|
resp := domainResponse{
|
|
ID: d.ID.String(), ProviderAccountID: d.ProviderAccountID.String(),
|
|
ZoneName: d.ZoneName, ZoneID: d.ZoneID, LastCheckStatus: d.LastCheckStatus,
|
|
}
|
|
if d.TemplateID != nil {
|
|
s := d.TemplateID.String()
|
|
resp.TemplateID = &s
|
|
}
|
|
return resp
|
|
}
|
|
|
|
// parseOptionalUUID parses s (may be nil/empty) into *uuid.UUID; returns ok=false on invalid input.
|
|
func parseOptionalUUID(s *string) (*uuid.UUID, bool) {
|
|
if s == nil || *s == "" {
|
|
return nil, true
|
|
}
|
|
id, err := uuid.Parse(*s)
|
|
if err != nil {
|
|
return nil, false
|
|
}
|
|
return &id, true
|
|
}
|