Add cusotmizable cname target domain
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -17,6 +17,7 @@ package probod
|
|||||||
type customDomainsConfig struct {
|
type customDomainsConfig struct {
|
||||||
RenewalInterval int `json:"renewal-interval"`
|
RenewalInterval int `json:"renewal-interval"`
|
||||||
ProvisionInterval int `json:"provision-interval"`
|
ProvisionInterval int `json:"provision-interval"`
|
||||||
|
CnameTarget string `json:"cname-target"`
|
||||||
ACME acmeConfig `json:"acme"`
|
ACME acmeConfig `json:"acme"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -309,9 +309,8 @@ func (impl *Implm) Run(
|
|||||||
ConnectorRegistry: defaultConnectorRegistry,
|
ConnectorRegistry: defaultConnectorRegistry,
|
||||||
Agent: agent,
|
Agent: agent,
|
||||||
SafeRedirect: &saferedirect.SafeRedirect{AllowedHost: impl.cfg.Hostname},
|
SafeRedirect: &saferedirect.SafeRedirect{AllowedHost: impl.cfg.Hostname},
|
||||||
|
CustomDomainCname: impl.cfg.CustomDomains.CnameTarget,
|
||||||
Logger: l.Named("http.server"),
|
Logger: l.Named("http.server"),
|
||||||
PgClient: pgClient,
|
|
||||||
EncryptionKey: impl.cfg.EncryptionKey,
|
|
||||||
Auth: api.ConsoleAuthConfig{
|
Auth: api.ConsoleAuthConfig{
|
||||||
CookieName: impl.cfg.Auth.Cookie.Name,
|
CookieName: impl.cfg.Auth.Cookie.Name,
|
||||||
CookieDomain: impl.cfg.Auth.Cookie.Domain,
|
CookieDomain: impl.cfg.Auth.Cookie.Domain,
|
||||||
|
|||||||
@@ -53,15 +53,16 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
Config struct {
|
Config struct {
|
||||||
AllowedOrigins []string
|
AllowedOrigins []string
|
||||||
Probo *probo.Service
|
Probo *probo.Service
|
||||||
Usrmgr *usrmgr.Service
|
Usrmgr *usrmgr.Service
|
||||||
Trust *trust.Service
|
Trust *trust.Service
|
||||||
Auth ConsoleAuthConfig
|
Auth ConsoleAuthConfig
|
||||||
TrustAuth TrustAuthConfig
|
TrustAuth TrustAuthConfig
|
||||||
ConnectorRegistry *connector.ConnectorRegistry
|
ConnectorRegistry *connector.ConnectorRegistry
|
||||||
SafeRedirect *saferedirect.SafeRedirect
|
SafeRedirect *saferedirect.SafeRedirect
|
||||||
Logger *log.Logger
|
CustomDomainCname string
|
||||||
|
Logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
Server struct {
|
Server struct {
|
||||||
@@ -154,6 +155,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
},
|
},
|
||||||
s.cfg.ConnectorRegistry,
|
s.cfg.ConnectorRegistry,
|
||||||
s.cfg.SafeRedirect,
|
s.cfg.SafeRedirect,
|
||||||
|
s.cfg.CustomDomainCname,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -53,9 +53,10 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
Resolver struct {
|
Resolver struct {
|
||||||
proboSvc *probo.Service
|
proboSvc *probo.Service
|
||||||
usrmgrSvc *usrmgr.Service
|
usrmgrSvc *usrmgr.Service
|
||||||
authCfg AuthConfig
|
authCfg AuthConfig
|
||||||
|
customDomainCname string
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxKey struct{ name string }
|
ctxKey struct{ name string }
|
||||||
@@ -84,6 +85,7 @@ func NewMux(
|
|||||||
authCfg AuthConfig,
|
authCfg AuthConfig,
|
||||||
connectorRegistry *connector.ConnectorRegistry,
|
connectorRegistry *connector.ConnectorRegistry,
|
||||||
safeRedirect *saferedirect.SafeRedirect,
|
safeRedirect *saferedirect.SafeRedirect,
|
||||||
|
customDomainCname string,
|
||||||
) *chi.Mux {
|
) *chi.Mux {
|
||||||
r := chi.NewMux()
|
r := chi.NewMux()
|
||||||
|
|
||||||
@@ -204,20 +206,21 @@ func NewMux(
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
r.Get("/", playground.Handler("GraphQL", "/api/console/v1/query"))
|
r.Get("/", playground.Handler("GraphQL", "/api/console/v1/query"))
|
||||||
r.Post("/query", graphqlHandler(logger, proboSvc, usrmgrSvc, authCfg))
|
r.Post("/query", graphqlHandler(logger, proboSvc, usrmgrSvc, authCfg, customDomainCname))
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func graphqlHandler(logger *log.Logger, proboSvc *probo.Service, usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
|
func graphqlHandler(logger *log.Logger, proboSvc *probo.Service, usrmgrSvc *usrmgr.Service, authCfg AuthConfig, customDomainCname string) http.HandlerFunc {
|
||||||
var mb int64 = 1 << 20
|
var mb int64 = 1 << 20
|
||||||
|
|
||||||
es := schema.NewExecutableSchema(
|
es := schema.NewExecutableSchema(
|
||||||
schema.Config{
|
schema.Config{
|
||||||
Resolvers: &Resolver{
|
Resolvers: &Resolver{
|
||||||
proboSvc: proboSvc,
|
proboSvc: proboSvc,
|
||||||
usrmgrSvc: usrmgrSvc,
|
usrmgrSvc: usrmgrSvc,
|
||||||
authCfg: authCfg,
|
authCfg: authCfg,
|
||||||
|
customDomainCname: customDomainCname,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
84
pkg/server/api/console/v1/types/custom_domain.go
Normal file
84
pkg/server/api/console/v1/types/custom_domain.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/getprobo/probo/pkg/coredata"
|
||||||
|
"github.com/getprobo/probo/pkg/gid"
|
||||||
|
"github.com/getprobo/probo/pkg/page"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewCustomDomainConnection(
|
||||||
|
p *page.Page[*coredata.CustomDomain, coredata.CustomDomainOrderField],
|
||||||
|
parentType any,
|
||||||
|
parentID gid.GID,
|
||||||
|
cnameTarget string,
|
||||||
|
) *CustomDomainConnection {
|
||||||
|
var edges = make([]*CustomDomainEdge, len(p.Data))
|
||||||
|
|
||||||
|
for i := range edges {
|
||||||
|
edges[i] = NewCustomDomainEdge(p.Data[i], p.Cursor.OrderBy.Field, cnameTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CustomDomainConnection{
|
||||||
|
Edges: edges,
|
||||||
|
PageInfo: NewPageInfo(p),
|
||||||
|
TotalCount: len(p.Data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCustomDomainEdge(
|
||||||
|
d *coredata.CustomDomain,
|
||||||
|
orderBy coredata.CustomDomainOrderField,
|
||||||
|
cnameTarget string,
|
||||||
|
) *CustomDomainEdge {
|
||||||
|
return &CustomDomainEdge{
|
||||||
|
Cursor: d.CursorKey(orderBy),
|
||||||
|
Node: NewCustomDomain(d, cnameTarget),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCustomDomain(d *coredata.CustomDomain, cnameTarget string) *CustomDomain {
|
||||||
|
result := &CustomDomain{
|
||||||
|
ID: d.ID,
|
||||||
|
Domain: d.Domain,
|
||||||
|
IsActive: d.IsActive,
|
||||||
|
SslStatus: d.SSLStatus,
|
||||||
|
CreatedAt: d.CreatedAt,
|
||||||
|
UpdatedAt: d.UpdatedAt,
|
||||||
|
SslExpiresAt: d.SSLExpiresAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert DNS records
|
||||||
|
result.DNSRecords = convertDNSRecords(d, cnameTarget)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDNSRecords(d *coredata.CustomDomain, cnameTarget string) []*DNSRecordInstruction {
|
||||||
|
var records []*DNSRecordInstruction
|
||||||
|
|
||||||
|
// For HTTP-01 challenges, we just need the domain to point to our servers via CNAME
|
||||||
|
record := &DNSRecordInstruction{
|
||||||
|
Type: "CNAME",
|
||||||
|
Name: d.Domain,
|
||||||
|
Value: cnameTarget,
|
||||||
|
TTL: 300,
|
||||||
|
Purpose: "Point domain to Probo servers",
|
||||||
|
}
|
||||||
|
records = append(records, record)
|
||||||
|
|
||||||
|
return records
|
||||||
|
}
|
||||||
@@ -3325,7 +3325,7 @@ func (r *mutationResolver) CreateCustomDomain(ctx context.Context, input types.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
edge := &types.CustomDomainEdge{
|
edge := &types.CustomDomainEdge{
|
||||||
Node: types.NewCustomDomain(domain),
|
Node: types.NewCustomDomain(domain, r.customDomainCname),
|
||||||
Cursor: page.NewCursorKey(domain.ID, domain.CreatedAt),
|
Cursor: page.NewCursorKey(domain.ID, domain.CreatedAt),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4032,7 +4032,7 @@ func (r *organizationResolver) CustomDomains(ctx context.Context, obj *types.Org
|
|||||||
return nil, fmt.Errorf("failed to list custom domains: %w", err)
|
return nil, fmt.Errorf("failed to list custom domains: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.NewCustomDomainConnection(page, r, obj.ID), nil
|
return types.NewCustomDomainConnection(page, r, obj.ID, r.customDomainCname), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalCount is the resolver for the totalCount field.
|
// TotalCount is the resolver for the totalCount field.
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ type Config struct {
|
|||||||
ConnectorRegistry *connector.ConnectorRegistry
|
ConnectorRegistry *connector.ConnectorRegistry
|
||||||
Agent *agents.Agent
|
Agent *agents.Agent
|
||||||
SafeRedirect *saferedirect.SafeRedirect
|
SafeRedirect *saferedirect.SafeRedirect
|
||||||
|
CustomDomainCname string
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ func NewServer(cfg Config) (*Server, error) {
|
|||||||
TrustAuth: cfg.TrustAuth,
|
TrustAuth: cfg.TrustAuth,
|
||||||
ConnectorRegistry: cfg.ConnectorRegistry,
|
ConnectorRegistry: cfg.ConnectorRegistry,
|
||||||
SafeRedirect: cfg.SafeRedirect,
|
SafeRedirect: cfg.SafeRedirect,
|
||||||
|
CustomDomainCname: cfg.CustomDomainCname,
|
||||||
Logger: cfg.Logger.Named("api"),
|
Logger: cfg.Logger.Named("api"),
|
||||||
}
|
}
|
||||||
apiServer, err := api.NewServer(apiCfg)
|
apiServer, err := api.NewServer(apiCfg)
|
||||||
|
|||||||
Reference in New Issue
Block a user