diff --git a/management/internals/modules/services/domains/api.go b/management/internals/modules/services/domains/api.go new file mode 100644 index 000000000..b810f1df8 --- /dev/null +++ b/management/internals/modules/services/domains/api.go @@ -0,0 +1,124 @@ +package domains + +import ( + "encoding/json" + "net/http" + + "github.com/gorilla/mux" + nbcontext "github.com/netbirdio/netbird/management/server/context" + "github.com/netbirdio/netbird/shared/management/http/api" + "github.com/netbirdio/netbird/shared/management/http/util" + "github.com/netbirdio/netbird/shared/management/status" +) + +type handler struct { + manager manager +} + +func RegisterEndpoints(router *mux.Router) { + h := &handler{} + + router.HandleFunc("/domains", h.getAllDomains).Methods("GET", "OPTIONS") + router.HandleFunc("/domains", h.createCustomDomain).Methods("POST", "OPTIONS") + router.HandleFunc("/domains/{domainId}", h.deleteCustomDomain).Methods("DELETE", "OPTIONS") + router.HandleFunc("/domains/{domainId}/validate", h.triggerCustomDomainValidation).Methods("GET", "OPTIONS") +} + +func domainTypeToApi(t domainType) api.ReverseProxyDomainType { + switch t { + case domainTypeCustom: + return api.ReverseProxyDomainTypeCustom + case domainTypeFree: + return api.ReverseProxyDomainTypeFree + } + // By default return as a "free" domain as that is more restrictive. + // TODO: is this correct? + return api.ReverseProxyDomainTypeFree +} + +func domainToApi(d domain) api.ReverseProxyDomain { + return api.ReverseProxyDomain{ + Domain: d.Domain, + Id: d.ID, + Type: domainTypeToApi(d.Type), + Validated: d.Validated, + } +} + +func (h *handler) getAllDomains(w http.ResponseWriter, r *http.Request) { + userAuth, err := nbcontext.GetUserAuthFromContext(r.Context()) + if err != nil { + util.WriteError(r.Context(), err, w) + return + } + + domains, err := h.manager.GetDomains(r.Context(), userAuth.AccountId) + + var ret []api.ReverseProxyDomain + for _, d := range domains { + ret = append(ret, domainToApi(d)) + } + + util.WriteJSONObject(r.Context(), w, ret) +} + +func (h *handler) createCustomDomain(w http.ResponseWriter, r *http.Request) { + userAuth, err := nbcontext.GetUserAuthFromContext(r.Context()) + if err != nil { + util.WriteError(r.Context(), err, w) + return + } + + var req api.PostApiReverseProxyDomainsJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w) + return + } + + domain, err := h.manager.CreateDomain(r.Context(), userAuth.AccountId, req.Domain) + if err != nil { + util.WriteError(r.Context(), err, w) + return + } + + util.WriteJSONObject(r.Context(), w, domainToApi(domain)) +} + +func (h *handler) deleteCustomDomain(w http.ResponseWriter, r *http.Request) { + userAuth, err := nbcontext.GetUserAuthFromContext(r.Context()) + if err != nil { + util.WriteError(r.Context(), err, w) + return + } + + domainID := mux.Vars(r)["domainId"] + if domainID == "" { + util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "domain ID is required"), w) + return + } + + if err := h.manager.DeleteDomain(r.Context(), userAuth.AccountId, domainID); err != nil { + util.WriteError(r.Context(), err, w) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +func (h *handler) triggerCustomDomainValidation(w http.ResponseWriter, r *http.Request) { + userAuth, err := nbcontext.GetUserAuthFromContext(r.Context()) + if err != nil { + util.WriteError(r.Context(), err, w) + return + } + + domainID := mux.Vars(r)["domainId"] + if domainID == "" { + util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "domain ID is required"), w) + return + } + + go h.manager.ValidateDomain(userAuth.AccountId, domainID) + + w.WriteHeader(http.StatusAccepted) +} diff --git a/management/internals/modules/services/domains/manager.go b/management/internals/modules/services/domains/manager.go new file mode 100644 index 000000000..1d6fc13c9 --- /dev/null +++ b/management/internals/modules/services/domains/manager.go @@ -0,0 +1,109 @@ +package domains + +import ( + "context" + "fmt" +) + +type domainType string + +const ( + domainTypeFree domainType = "free" + domainTypeCustom domainType = "custom" +) + +type domain struct { + ID string + Domain string + Type domainType + Validated bool +} + +type store interface { + GetAccountDomainNonce(ctx context.Context, accountID string) (nonce string, err error) + GetCustomDomain(ctx context.Context, accountID string, domainID string) (domain, error) + ListFreeDomains(ctx context.Context, accountID string) ([]string, error) + ListCustomDomains(ctx context.Context, accountID string) ([]domain, error) + CreateCustomDomain(ctx context.Context, accountID string, domainName string, validated bool) (domain, error) + UpdateCustomDomain(ctx context.Context, accountID string, d domain) (domain, error) + DeleteCustomDomain(ctx context.Context, accountID string, domainID string) error +} + +type manager struct { + store store + validator Validator +} + +func (m manager) GetDomains(ctx context.Context, accountID string) ([]domain, error) { + nonce, err := m.store.GetAccountDomainNonce(ctx, accountID) + if err != nil { + return nil, fmt.Errorf("get account domain nonce: %w", err) + } + free, err := m.store.ListFreeDomains(ctx, accountID) + if err != nil { + return nil, fmt.Errorf("list free domains: %w", err) + } + domains, err := m.store.ListCustomDomains(ctx, accountID) + if err != nil { + // TODO: check for "no records" type error. Because that is a success condition. + return nil, fmt.Errorf("list custom domains: %w", err) + } + + // Prepend each free domain with the account nonce and then add it to the domain + // array to be returned. + // This account nonce is added to free domains to prevent users being able to + // query free domain usage across accounts and simplifies tracking free domain + // usage across accounts. + for _, name := range free { + domains = append(domains, domain{ + Domain: nonce + "." + name, + Type: domainTypeFree, + Validated: true, + }) + } + return domains, nil +} + +func (m manager) CreateDomain(ctx context.Context, accountID, domainName string) (domain, error) { + // Attempt an initial validation; however, a failure is still acceptable for creation + // because the user may not yet have configured their DNS records, or the DNS update + // has not yet reached the servers that are queried by the validation resolver. + var validated bool + // TODO: retrieve in use reverse proxy addresses from somewhere! + var reverseProxyAddresses []string + if m.validator.IsValid(ctx, domainName, reverseProxyAddresses) { + validated = true + } + + d, err := m.store.CreateCustomDomain(ctx, accountID, domainName, validated) + if err != nil { + return d, fmt.Errorf("create domain in store: %w", err) + } + + return d, nil +} + +func (m manager) DeleteDomain(ctx context.Context, accountID, domainID string) error { + if err := m.store.DeleteCustomDomain(ctx, accountID, domainID); err != nil { + // TODO: check for "no records" type error. Because that is a success condition. + return fmt.Errorf("delete domain from store: %w", err) + } + return nil +} + +func (m manager) ValidateDomain(accountID, domainID string) { + d, err := m.store.GetCustomDomain(context.Background(), accountID, domainID) + if err != nil { + // TODO: something? Log? + return + } + // TODO: retrieve in use reverse proxy addresses from somewhere! + var reverseProxyAddresses []string + if m.validator.IsValid(context.Background(), d.Domain, reverseProxyAddresses) { + d.Validated = true + if _, err := m.store.UpdateCustomDomain(context.Background(), accountID, d); err != nil { + // TODO: something? Log? + return + } + } +} diff --git a/management/internals/modules/services/domainvalidation/validator.go b/management/internals/modules/services/domains/validator.go similarity index 76% rename from management/internals/modules/services/domainvalidation/validator.go rename to management/internals/modules/services/domains/validator.go index 682c4417f..bc58e9b07 100644 --- a/management/internals/modules/services/domainvalidation/validator.go +++ b/management/internals/modules/services/domains/validator.go @@ -1,13 +1,4 @@ -// Package domainvalidation provides a mechanism for verifying ownership of -// a domain. -// It is intended to be used before custom domains can be assigned to reverse -// proxy services. -// Acceptable domains should be set to the known domains that reverse proxy -// servers are hosted at. -// -// After a custom domain is validated, it should be pinned to a single account -// to prevent domain abuse across accounts. -package domainvalidation +package domains import ( "context" diff --git a/management/internals/modules/services/domainvalidation/validator_test.go b/management/internals/modules/services/domains/validator_test.go similarity index 91% rename from management/internals/modules/services/domainvalidation/validator_test.go rename to management/internals/modules/services/domains/validator_test.go index c9e7d0419..9a7dec79c 100644 --- a/management/internals/modules/services/domainvalidation/validator_test.go +++ b/management/internals/modules/services/domains/validator_test.go @@ -1,10 +1,10 @@ -package domainvalidation_test +package domains_test import ( "context" "testing" - "github.com/netbirdio/netbird/management/internals/modules/services/domainvalidation" + "github.com/netbirdio/netbird/management/internals/modules/services/domains" ) type resolver struct { @@ -46,7 +46,7 @@ func TestIsValid(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { - validator := domainvalidation.NewValidator(test.resolver) + validator := domains.NewValidator(test.resolver) actual := validator.IsValid(t.Context(), test.domain, test.accept) if test.expect != actual { t.Errorf("Incorrect return value:\nexpect: %v\nactual: %v", test.expect, actual) diff --git a/shared/management/http/api/openapi.yml b/shared/management/http/api/openapi.yml index 192caee5a..f3dba3d0e 100644 --- a/shared/management/http/api/openapi.yml +++ b/shared/management/http/api/openapi.yml @@ -2914,6 +2914,40 @@ components: description: Whether link auth is enabled required: - enabled + ReverseProxyDomainType: + type: string + description: Type of Reverse Proxy Domain + enum: + - free + - custom + example: free + ReverseProxyDomain: + type: object + properties: + id: + type: string + description: Domain ID + domain: + type: string + description: Domain name + validated: + type: boolean + description: Whether the domain has been validated + type: + $ref: '#/components/schemas/ReverseProxyDomainType' + required: + - id + - domain + - validated + - type + ReverseProxyDomainRequest: + type: object + properties: + domain: + type: string + description: Domain name + required: + - domain InstanceStatus: type: object description: Instance status information @@ -6651,3 +6685,116 @@ paths: "$ref": "#/components/responses/not_found" '500': "$ref": "#/components/responses/internal_error" + /api/reverse-proxy/domains: + get: + summary: Retrieve Reverse Proxy Domains + description: Get information about domains that can be used for Reverse Proxy endpoints. + tags: [ Reverse Proxy ] + security: + - BearerAuth: [ ] + - TokenAuth: [ ] + responses: + '200': + description: A JSON Array of ReverseProxyDomains + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ReverseProxyDomain' + '400': + "$ref": "#/components/responses/bad_request" + '401': + "$ref": "#/components/responses/requires_authentication" + '403': + "$ref": "#/components/responses/forbidden" + '404': + "$ref": "#/components/responses/not_found" + '500': + "$ref": "#/components/responses/internal_error" + post: + summary: Create a Custom domain + description: Create a new Custom domain for use with Reverse Proxy endpoints, this will trigger an initial validation check + tags: [ Reverse Proxy ] + security: + - BearerAuth: [ ] + - TokenAuth: [ ] + requestBody: + description: Custom domain creation request + content: + application/json: + schema: + $ref: '#/components/schemas/ReverseProxyDomainRequest' + responses: + '200': + description: Reverse proxy created + content: + application/json: + schema: + $ref: '#/components/schemas/ReverseProxy' + '400': + "$ref": "#/components/responses/bad_request" + '401': + "$ref": "#/components/responses/requires_authentication" + '403': + "$ref": "#/components/responses/forbidden" + '404': + "$ref": "#/components/responses/not_found" + '500': + "$ref": "#/components/responses/internal_error" + /api/reverse-proxy/domains/{domainId}: + delete: + summary: Delete a Custom domain + description: Delete an existing reverse proxy custom domain + tags: [ Reverse Proxy ] + security: + - BearerAuth: [ ] + - TokenAuth: [ ] + parameters: + - in: path + name: domainId + required: true + schema: + type: string + description: The custom domain ID + responses: + '204': + description: Reverse proxy custom domain deleted + '400': + "$ref": "#/components/responses/bad_request" + '401': + "$ref": "#/components/responses/requires_authentication" + '403': + "$ref": "#/components/responses/forbidden" + '404': + "$ref": "#/components/responses/not_found" + '500': + "$ref": "#/components/responses/internal_error" + /api/reverse-proxy/domains/{domainId}/validate: + get: + summary: Validate a custom domain + description: Trigger domain ownership validation for a custom domain + tags: [ Reverse Proxy ] + security: + - BearerAuth: [ ] + - TokenAuth: [ ] + parameters: + - in: path + name: domainId + required: true + schema: + type: string + description: The custom domain ID + responses: + '202': + description: Reverse proxy custom domain validation triggered + '400': + "$ref": "#/components/responses/bad_request" + '401': + "$ref": "#/components/responses/requires_authentication" + '403': + "$ref": "#/components/responses/forbidden" + '404': + "$ref": "#/components/responses/not_found" + '500': + "$ref": "#/components/responses/internal_error" diff --git a/shared/management/http/api/types.gen.go b/shared/management/http/api/types.gen.go index e8c044b32..fc84d0eed 100644 --- a/shared/management/http/api/types.gen.go +++ b/shared/management/http/api/types.gen.go @@ -1,14 +1,10 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/deepmap/oapi-codegen version v1.11.1-0.20220912230023-4a1477f6a8ba DO NOT EDIT. package api import ( - "encoding/json" - "errors" "time" - - "github.com/oapi-codegen/runtime" ) const ( @@ -25,115 +21,56 @@ const ( // Defines values for EventActivityCode. const ( - EventActivityCodeAccountCreate EventActivityCode = "account.create" - EventActivityCodeAccountDelete EventActivityCode = "account.delete" - EventActivityCodeAccountDnsDomainUpdate EventActivityCode = "account.dns.domain.update" - EventActivityCodeAccountNetworkRangeUpdate EventActivityCode = "account.network.range.update" - EventActivityCodeAccountPeerInactivityExpirationDisable EventActivityCode = "account.peer.inactivity.expiration.disable" - EventActivityCodeAccountPeerInactivityExpirationEnable EventActivityCode = "account.peer.inactivity.expiration.enable" - EventActivityCodeAccountPeerInactivityExpirationUpdate EventActivityCode = "account.peer.inactivity.expiration.update" - EventActivityCodeAccountSettingGroupPropagationDisable EventActivityCode = "account.setting.group.propagation.disable" - EventActivityCodeAccountSettingGroupPropagationEnable EventActivityCode = "account.setting.group.propagation.enable" - EventActivityCodeAccountSettingLazyConnectionDisable EventActivityCode = "account.setting.lazy.connection.disable" - EventActivityCodeAccountSettingLazyConnectionEnable EventActivityCode = "account.setting.lazy.connection.enable" - EventActivityCodeAccountSettingPeerApprovalDisable EventActivityCode = "account.setting.peer.approval.disable" - EventActivityCodeAccountSettingPeerApprovalEnable EventActivityCode = "account.setting.peer.approval.enable" - EventActivityCodeAccountSettingPeerLoginExpirationDisable EventActivityCode = "account.setting.peer.login.expiration.disable" - EventActivityCodeAccountSettingPeerLoginExpirationEnable EventActivityCode = "account.setting.peer.login.expiration.enable" - EventActivityCodeAccountSettingPeerLoginExpirationUpdate EventActivityCode = "account.setting.peer.login.expiration.update" - EventActivityCodeAccountSettingRoutingPeerDnsResolutionDisable EventActivityCode = "account.setting.routing.peer.dns.resolution.disable" - EventActivityCodeAccountSettingRoutingPeerDnsResolutionEnable EventActivityCode = "account.setting.routing.peer.dns.resolution.enable" - EventActivityCodeAccountSettingsAutoVersionUpdate EventActivityCode = "account.settings.auto.version.update" - EventActivityCodeDashboardLogin EventActivityCode = "dashboard.login" - EventActivityCodeDnsSettingDisabledManagementGroupAdd EventActivityCode = "dns.setting.disabled.management.group.add" - EventActivityCodeDnsSettingDisabledManagementGroupDelete EventActivityCode = "dns.setting.disabled.management.group.delete" - EventActivityCodeDnsZoneCreate EventActivityCode = "dns.zone.create" - EventActivityCodeDnsZoneDelete EventActivityCode = "dns.zone.delete" - EventActivityCodeDnsZoneRecordCreate EventActivityCode = "dns.zone.record.create" - EventActivityCodeDnsZoneRecordDelete EventActivityCode = "dns.zone.record.delete" - EventActivityCodeDnsZoneRecordUpdate EventActivityCode = "dns.zone.record.update" - EventActivityCodeDnsZoneUpdate EventActivityCode = "dns.zone.update" - EventActivityCodeGroupAdd EventActivityCode = "group.add" - EventActivityCodeGroupDelete EventActivityCode = "group.delete" - EventActivityCodeGroupUpdate EventActivityCode = "group.update" - EventActivityCodeIdentityproviderCreate EventActivityCode = "identityprovider.create" - EventActivityCodeIdentityproviderDelete EventActivityCode = "identityprovider.delete" - EventActivityCodeIdentityproviderUpdate EventActivityCode = "identityprovider.update" - EventActivityCodeIntegrationCreate EventActivityCode = "integration.create" - EventActivityCodeIntegrationDelete EventActivityCode = "integration.delete" - EventActivityCodeIntegrationUpdate EventActivityCode = "integration.update" - EventActivityCodeNameserverGroupAdd EventActivityCode = "nameserver.group.add" - EventActivityCodeNameserverGroupDelete EventActivityCode = "nameserver.group.delete" - EventActivityCodeNameserverGroupUpdate EventActivityCode = "nameserver.group.update" - EventActivityCodeNetworkCreate EventActivityCode = "network.create" - EventActivityCodeNetworkDelete EventActivityCode = "network.delete" - EventActivityCodeNetworkResourceCreate EventActivityCode = "network.resource.create" - EventActivityCodeNetworkResourceDelete EventActivityCode = "network.resource.delete" - EventActivityCodeNetworkResourceUpdate EventActivityCode = "network.resource.update" - EventActivityCodeNetworkRouterCreate EventActivityCode = "network.router.create" - EventActivityCodeNetworkRouterDelete EventActivityCode = "network.router.delete" - EventActivityCodeNetworkRouterUpdate EventActivityCode = "network.router.update" - EventActivityCodeNetworkUpdate EventActivityCode = "network.update" - EventActivityCodePeerApprovalRevoke EventActivityCode = "peer.approval.revoke" - EventActivityCodePeerApprove EventActivityCode = "peer.approve" - EventActivityCodePeerGroupAdd EventActivityCode = "peer.group.add" - EventActivityCodePeerGroupDelete EventActivityCode = "peer.group.delete" - EventActivityCodePeerInactivityExpirationDisable EventActivityCode = "peer.inactivity.expiration.disable" - EventActivityCodePeerInactivityExpirationEnable EventActivityCode = "peer.inactivity.expiration.enable" - EventActivityCodePeerIpUpdate EventActivityCode = "peer.ip.update" - EventActivityCodePeerJobCreate EventActivityCode = "peer.job.create" - EventActivityCodePeerLoginExpirationDisable EventActivityCode = "peer.login.expiration.disable" - EventActivityCodePeerLoginExpirationEnable EventActivityCode = "peer.login.expiration.enable" - EventActivityCodePeerLoginExpire EventActivityCode = "peer.login.expire" - EventActivityCodePeerRename EventActivityCode = "peer.rename" - EventActivityCodePeerSetupkeyAdd EventActivityCode = "peer.setupkey.add" - EventActivityCodePeerSshDisable EventActivityCode = "peer.ssh.disable" - EventActivityCodePeerSshEnable EventActivityCode = "peer.ssh.enable" - EventActivityCodePeerUserAdd EventActivityCode = "peer.user.add" - EventActivityCodePersonalAccessTokenCreate EventActivityCode = "personal.access.token.create" - EventActivityCodePersonalAccessTokenDelete EventActivityCode = "personal.access.token.delete" - EventActivityCodePolicyAdd EventActivityCode = "policy.add" - EventActivityCodePolicyDelete EventActivityCode = "policy.delete" - EventActivityCodePolicyUpdate EventActivityCode = "policy.update" - EventActivityCodePostureCheckCreate EventActivityCode = "posture.check.create" - EventActivityCodePostureCheckDelete EventActivityCode = "posture.check.delete" - EventActivityCodePostureCheckUpdate EventActivityCode = "posture.check.update" - EventActivityCodeResourceGroupAdd EventActivityCode = "resource.group.add" - EventActivityCodeResourceGroupDelete EventActivityCode = "resource.group.delete" - EventActivityCodeRouteAdd EventActivityCode = "route.add" - EventActivityCodeRouteDelete EventActivityCode = "route.delete" - EventActivityCodeRouteUpdate EventActivityCode = "route.update" - EventActivityCodeRuleAdd EventActivityCode = "rule.add" - EventActivityCodeRuleDelete EventActivityCode = "rule.delete" - EventActivityCodeRuleUpdate EventActivityCode = "rule.update" - EventActivityCodeServiceUserCreate EventActivityCode = "service.user.create" - EventActivityCodeServiceUserDelete EventActivityCode = "service.user.delete" - EventActivityCodeSetupkeyAdd EventActivityCode = "setupkey.add" - EventActivityCodeSetupkeyDelete EventActivityCode = "setupkey.delete" - EventActivityCodeSetupkeyGroupAdd EventActivityCode = "setupkey.group.add" - EventActivityCodeSetupkeyGroupDelete EventActivityCode = "setupkey.group.delete" - EventActivityCodeSetupkeyOveruse EventActivityCode = "setupkey.overuse" - EventActivityCodeSetupkeyRevoke EventActivityCode = "setupkey.revoke" - EventActivityCodeSetupkeyUpdate EventActivityCode = "setupkey.update" - EventActivityCodeTransferredOwnerRole EventActivityCode = "transferred.owner.role" - EventActivityCodeUserApprove EventActivityCode = "user.approve" - EventActivityCodeUserBlock EventActivityCode = "user.block" - EventActivityCodeUserCreate EventActivityCode = "user.create" - EventActivityCodeUserDelete EventActivityCode = "user.delete" - EventActivityCodeUserGroupAdd EventActivityCode = "user.group.add" - EventActivityCodeUserGroupDelete EventActivityCode = "user.group.delete" - EventActivityCodeUserInvite EventActivityCode = "user.invite" - EventActivityCodeUserInviteLinkAccept EventActivityCode = "user.invite.link.accept" - EventActivityCodeUserInviteLinkCreate EventActivityCode = "user.invite.link.create" - EventActivityCodeUserInviteLinkDelete EventActivityCode = "user.invite.link.delete" - EventActivityCodeUserInviteLinkRegenerate EventActivityCode = "user.invite.link.regenerate" - EventActivityCodeUserJoin EventActivityCode = "user.join" - EventActivityCodeUserPasswordChange EventActivityCode = "user.password.change" - EventActivityCodeUserPeerDelete EventActivityCode = "user.peer.delete" - EventActivityCodeUserPeerLogin EventActivityCode = "user.peer.login" - EventActivityCodeUserReject EventActivityCode = "user.reject" - EventActivityCodeUserRoleUpdate EventActivityCode = "user.role.update" - EventActivityCodeUserUnblock EventActivityCode = "user.unblock" + EventActivityCodeAccountCreate EventActivityCode = "account.create" + EventActivityCodeAccountSettingPeerLoginExpirationDisable EventActivityCode = "account.setting.peer.login.expiration.disable" + EventActivityCodeAccountSettingPeerLoginExpirationEnable EventActivityCode = "account.setting.peer.login.expiration.enable" + EventActivityCodeAccountSettingPeerLoginExpirationUpdate EventActivityCode = "account.setting.peer.login.expiration.update" + EventActivityCodeDnsSettingDisabledManagementGroupAdd EventActivityCode = "dns.setting.disabled.management.group.add" + EventActivityCodeDnsSettingDisabledManagementGroupDelete EventActivityCode = "dns.setting.disabled.management.group.delete" + EventActivityCodeGroupAdd EventActivityCode = "group.add" + EventActivityCodeGroupUpdate EventActivityCode = "group.update" + EventActivityCodeNameserverGroupAdd EventActivityCode = "nameserver.group.add" + EventActivityCodeNameserverGroupDelete EventActivityCode = "nameserver.group.delete" + EventActivityCodeNameserverGroupUpdate EventActivityCode = "nameserver.group.update" + EventActivityCodePeerLoginExpirationDisable EventActivityCode = "peer.login.expiration.disable" + EventActivityCodePeerLoginExpirationEnable EventActivityCode = "peer.login.expiration.enable" + EventActivityCodePeerLoginExpire EventActivityCode = "peer.login.expire" + EventActivityCodePeerRename EventActivityCode = "peer.rename" + EventActivityCodePeerSshDisable EventActivityCode = "peer.ssh.disable" + EventActivityCodePeerSshEnable EventActivityCode = "peer.ssh.enable" + EventActivityCodePersonalAccessTokenCreate EventActivityCode = "personal.access.token.create" + EventActivityCodePersonalAccessTokenDelete EventActivityCode = "personal.access.token.delete" + EventActivityCodePolicyAdd EventActivityCode = "policy.add" + EventActivityCodePolicyDelete EventActivityCode = "policy.delete" + EventActivityCodePolicyUpdate EventActivityCode = "policy.update" + EventActivityCodeRouteAdd EventActivityCode = "route.add" + EventActivityCodeRouteDelete EventActivityCode = "route.delete" + EventActivityCodeRouteUpdate EventActivityCode = "route.update" + EventActivityCodeRuleAdd EventActivityCode = "rule.add" + EventActivityCodeRuleDelete EventActivityCode = "rule.delete" + EventActivityCodeRuleUpdate EventActivityCode = "rule.update" + EventActivityCodeServiceCreate EventActivityCode = "service.create" + EventActivityCodeServiceDelete EventActivityCode = "service.delete" + EventActivityCodeServiceUpdate EventActivityCode = "service.update" + EventActivityCodeServiceUserCreate EventActivityCode = "service.user.create" + EventActivityCodeServiceUserDelete EventActivityCode = "service.user.delete" + EventActivityCodeSetupkeyAdd EventActivityCode = "setupkey.add" + EventActivityCodeSetupkeyGroupAdd EventActivityCode = "setupkey.group.add" + EventActivityCodeSetupkeyGroupDelete EventActivityCode = "setupkey.group.delete" + EventActivityCodeSetupkeyOveruse EventActivityCode = "setupkey.overuse" + EventActivityCodeSetupkeyPeerAdd EventActivityCode = "setupkey.peer.add" + EventActivityCodeSetupkeyRevoke EventActivityCode = "setupkey.revoke" + EventActivityCodeSetupkeyUpdate EventActivityCode = "setupkey.update" + EventActivityCodeUserBlock EventActivityCode = "user.block" + EventActivityCodeUserGroupAdd EventActivityCode = "user.group.add" + EventActivityCodeUserGroupDelete EventActivityCode = "user.group.delete" + EventActivityCodeUserInvite EventActivityCode = "user.invite" + EventActivityCodeUserJoin EventActivityCode = "user.join" + EventActivityCodeUserPeerAdd EventActivityCode = "user.peer.add" + EventActivityCodeUserPeerDelete EventActivityCode = "user.peer.delete" + EventActivityCodeUserPeerLogin EventActivityCode = "user.peer.login" + EventActivityCodeUserRoleUpdate EventActivityCode = "user.role.update" + EventActivityCodeUserUnblock EventActivityCode = "user.unblock" ) // Defines values for GeoLocationCheckAction. @@ -188,13 +125,6 @@ const ( IngressPortAllocationRequestPortRangeProtocolUdp IngressPortAllocationRequestPortRangeProtocol = "udp" ) -// Defines values for JobResponseStatus. -const ( - JobResponseStatusFailed JobResponseStatus = "failed" - JobResponseStatusPending JobResponseStatus = "pending" - JobResponseStatusSucceeded JobResponseStatus = "succeeded" -) - // Defines values for NameserverNsType. const ( NameserverNsTypeUdp NameserverNsType = "udp" @@ -266,6 +196,32 @@ const ( ResourceTypeSubnet ResourceType = "subnet" ) +// Defines values for ReverseProxyAuthConfigType. +const ( + ReverseProxyAuthConfigTypeBearer ReverseProxyAuthConfigType = "bearer" + ReverseProxyAuthConfigTypeLink ReverseProxyAuthConfigType = "link" + ReverseProxyAuthConfigTypePassword ReverseProxyAuthConfigType = "password" + ReverseProxyAuthConfigTypePin ReverseProxyAuthConfigType = "pin" +) + +// Defines values for ReverseProxyDomainType. +const ( + ReverseProxyDomainTypeCustom ReverseProxyDomainType = "custom" + ReverseProxyDomainTypeFree ReverseProxyDomainType = "free" +) + +// Defines values for ReverseProxyTargetProtocol. +const ( + ReverseProxyTargetProtocolHttp ReverseProxyTargetProtocol = "http" + ReverseProxyTargetProtocolHttps ReverseProxyTargetProtocol = "https" +) + +// Defines values for ReverseProxyTargetTargetType. +const ( + ReverseProxyTargetTargetTypePeer ReverseProxyTargetTargetType = "peer" + ReverseProxyTargetTargetTypeResource ReverseProxyTargetTargetType = "resource" +) + // Defines values for UserStatus. const ( UserStatusActive UserStatus = "active" @@ -273,11 +229,6 @@ const ( UserStatusInvited UserStatus = "invited" ) -// Defines values for WorkloadType. -const ( - WorkloadTypeBundle WorkloadType = "bundle" -) - // Defines values for GetApiEventsNetworkTrafficParamsType. const ( GetApiEventsNetworkTrafficParamsTypeTYPEDROP GetApiEventsNetworkTrafficParamsType = "TYPE_DROP" @@ -446,45 +397,13 @@ type AvailablePorts struct { Udp int `json:"udp"` } -// BundleParameters These parameters control what gets included in the bundle and how it is processed. -type BundleParameters struct { - // Anonymize Whether sensitive data should be anonymized in the bundle. - Anonymize bool `json:"anonymize"` +// BearerAuthConfig defines model for BearerAuthConfig. +type BearerAuthConfig struct { + // DistributionGroups List of group IDs that can use bearer auth + DistributionGroups *[]string `json:"distribution_groups,omitempty"` - // BundleFor Whether to generate a bundle for the given timeframe. - BundleFor bool `json:"bundle_for"` - - // BundleForTime Time period in minutes for which to generate the bundle. - BundleForTime int `json:"bundle_for_time"` - - // LogFileCount Maximum number of log files to include in the bundle. - LogFileCount int `json:"log_file_count"` -} - -// BundleResult defines model for BundleResult. -type BundleResult struct { - UploadKey *string `json:"upload_key"` -} - -// BundleWorkloadRequest defines model for BundleWorkloadRequest. -type BundleWorkloadRequest struct { - // Parameters These parameters control what gets included in the bundle and how it is processed. - Parameters BundleParameters `json:"parameters"` - - // Type Identifies the type of workload the job will execute. - // Currently only `"bundle"` is supported. - Type WorkloadType `json:"type"` -} - -// BundleWorkloadResponse defines model for BundleWorkloadResponse. -type BundleWorkloadResponse struct { - // Parameters These parameters control what gets included in the bundle and how it is processed. - Parameters BundleParameters `json:"parameters"` - Result BundleResult `json:"result"` - - // Type Identifies the type of workload the job will execute. - // Currently only `"bundle"` is supported. - Type WorkloadType `json:"type"` + // Enabled Whether bearer auth is enabled + Enabled bool `json:"enabled"` } // Checks List of objects that perform the actual checks @@ -874,40 +793,12 @@ type InstanceStatus struct { SetupRequired bool `json:"setup_required"` } -// InstanceVersionInfo Version information for NetBird components -type InstanceVersionInfo struct { - // DashboardAvailableVersion The latest available version of the dashboard (from GitHub releases) - DashboardAvailableVersion *string `json:"dashboard_available_version,omitempty"` - - // ManagementAvailableVersion The latest available version of the management server (from GitHub releases) - ManagementAvailableVersion *string `json:"management_available_version,omitempty"` - - // ManagementCurrentVersion The current running version of the management server - ManagementCurrentVersion string `json:"management_current_version"` - - // ManagementUpdateAvailable Indicates if a newer management version is available - ManagementUpdateAvailable bool `json:"management_update_available"` +// LinkAuthConfig defines model for LinkAuthConfig. +type LinkAuthConfig struct { + // Enabled Whether link auth is enabled + Enabled bool `json:"enabled"` } -// JobRequest defines model for JobRequest. -type JobRequest struct { - Workload WorkloadRequest `json:"workload"` -} - -// JobResponse defines model for JobResponse. -type JobResponse struct { - CompletedAt *time.Time `json:"completed_at"` - CreatedAt time.Time `json:"created_at"` - FailedReason *string `json:"failed_reason"` - Id string `json:"id"` - Status JobResponseStatus `json:"status"` - TriggeredBy string `json:"triggered_by"` - Workload WorkloadResponse `json:"workload"` -} - -// JobResponseStatus defines model for JobResponse.Status. -type JobResponseStatus string - // Location Describe geographical location information type Location struct { // CityName Commonly used English name of the city @@ -1278,13 +1169,22 @@ type OSVersionCheck struct { Windows *MinKernelVersionCheck `json:"windows,omitempty"` } -// PasswordChangeRequest defines model for PasswordChangeRequest. -type PasswordChangeRequest struct { - // NewPassword The new password to set - NewPassword string `json:"new_password"` +// PINAuthConfig defines model for PINAuthConfig. +type PINAuthConfig struct { + // Enabled Whether PIN auth is enabled + Enabled bool `json:"enabled"` - // OldPassword The current password - OldPassword string `json:"old_password"` + // Pin PIN value + Pin string `json:"pin"` +} + +// PasswordAuthConfig defines model for PasswordAuthConfig. +type PasswordAuthConfig struct { + // Enabled Whether password auth is enabled + Enabled bool `json:"enabled"` + + // Password Auth password + Password string `json:"password"` } // Peer defines model for Peer. @@ -1848,6 +1748,111 @@ type Resource struct { // ResourceType defines model for ResourceType. type ResourceType string +// ReverseProxy defines model for ReverseProxy. +type ReverseProxy struct { + Auth ReverseProxyAuthConfig `json:"auth"` + + // Domain Domain for the reverse proxy + Domain string `json:"domain"` + + // Enabled Whether the reverse proxy is enabled + Enabled bool `json:"enabled"` + + // Id Reverse proxy ID + Id string `json:"id"` + + // Name Reverse proxy name + Name string `json:"name"` + + // Targets List of target backends for this reverse proxy + Targets []ReverseProxyTarget `json:"targets"` +} + +// ReverseProxyAuthConfig defines model for ReverseProxyAuthConfig. +type ReverseProxyAuthConfig struct { + BearerAuth *BearerAuthConfig `json:"bearer_auth,omitempty"` + LinkAuth *LinkAuthConfig `json:"link_auth,omitempty"` + PasswordAuth *PasswordAuthConfig `json:"password_auth,omitempty"` + PinAuth *PINAuthConfig `json:"pin_auth,omitempty"` + + // Type Authentication type + Type ReverseProxyAuthConfigType `json:"type"` +} + +// ReverseProxyAuthConfigType Authentication type +type ReverseProxyAuthConfigType string + +// ReverseProxyDomain defines model for ReverseProxyDomain. +type ReverseProxyDomain struct { + // Domain Domain name + Domain string `json:"domain"` + + // Id Domain ID + Id string `json:"id"` + + // Type Type of Reverse Proxy Domain + Type ReverseProxyDomainType `json:"type"` + + // Validated Whether the domain has been validated + Validated bool `json:"validated"` +} + +// ReverseProxyDomainRequest defines model for ReverseProxyDomainRequest. +type ReverseProxyDomainRequest struct { + // Domain Domain name + Domain string `json:"domain"` +} + +// ReverseProxyDomainType Type of Reverse Proxy Domain +type ReverseProxyDomainType string + +// ReverseProxyRequest defines model for ReverseProxyRequest. +type ReverseProxyRequest struct { + Auth ReverseProxyAuthConfig `json:"auth"` + + // Domain Domain for the reverse proxy + Domain string `json:"domain"` + + // Enabled Whether the reverse proxy is enabled + Enabled bool `json:"enabled"` + + // Name Reverse proxy name + Name string `json:"name"` + + // Targets List of target backends for this reverse proxy + Targets []ReverseProxyTarget `json:"targets"` +} + +// ReverseProxyTarget defines model for ReverseProxyTarget. +type ReverseProxyTarget struct { + // Enabled Whether this target is enabled + Enabled bool `json:"enabled"` + + // Host Backend ip or domain for this target + Host string `json:"host"` + + // Path URL path prefix for this target + Path *string `json:"path,omitempty"` + + // Port Backend port for this target + Port int `json:"port"` + + // Protocol Protocol to use when connecting to the backend + Protocol ReverseProxyTargetProtocol `json:"protocol"` + + // TargetId Target ID + TargetId string `json:"target_id"` + + // TargetType Target type (e.g., "peer", "resource") + TargetType ReverseProxyTargetTargetType `json:"target_type"` +} + +// ReverseProxyTargetProtocol Protocol to use when connecting to the backend +type ReverseProxyTargetProtocol string + +// ReverseProxyTargetTargetType Target type (e.g., "peer", "resource") +type ReverseProxyTargetTargetType string + // Route defines model for Route. type Route struct { // AccessControlGroups Access control group identifier associated with route. @@ -2185,99 +2190,6 @@ type UserCreateRequest struct { Role string `json:"role"` } -// UserInvite A user invite -type UserInvite struct { - // AutoGroups Group IDs to auto-assign to peers registered by this user - AutoGroups []string `json:"auto_groups"` - - // CreatedAt Invite creation time - CreatedAt time.Time `json:"created_at"` - - // Email User's email address - Email string `json:"email"` - - // Expired Whether the invite has expired - Expired bool `json:"expired"` - - // ExpiresAt Invite expiration time - ExpiresAt time.Time `json:"expires_at"` - - // Id Invite ID - Id string `json:"id"` - - // InviteToken The invite link to be shared with the user. Only returned when the invite is created or regenerated. - InviteToken *string `json:"invite_token,omitempty"` - - // Name User's full name - Name string `json:"name"` - - // Role User's NetBird account role - Role string `json:"role"` -} - -// UserInviteAcceptRequest Request to accept an invite and set password -type UserInviteAcceptRequest struct { - // Password The password the user wants to set. Must be at least 8 characters long and contain at least one uppercase letter, one digit, and one special character (any character that is not a letter or digit, including spaces). - Password string `json:"password"` -} - -// UserInviteAcceptResponse Response after accepting an invite -type UserInviteAcceptResponse struct { - // Success Whether the invite was accepted successfully - Success bool `json:"success"` -} - -// UserInviteCreateRequest Request to create a user invite link -type UserInviteCreateRequest struct { - // AutoGroups Group IDs to auto-assign to peers registered by this user - AutoGroups []string `json:"auto_groups"` - - // Email User's email address - Email string `json:"email"` - - // ExpiresIn Invite expiration time in seconds (default 72 hours) - ExpiresIn *int `json:"expires_in,omitempty"` - - // Name User's full name - Name string `json:"name"` - - // Role User's NetBird account role - Role string `json:"role"` -} - -// UserInviteInfo Public information about an invite -type UserInviteInfo struct { - // Email User's email address - Email string `json:"email"` - - // ExpiresAt Invite expiration time - ExpiresAt time.Time `json:"expires_at"` - - // InvitedBy Name of the user who sent the invite - InvitedBy string `json:"invited_by"` - - // Name User's full name - Name string `json:"name"` - - // Valid Whether the invite is still valid (not expired) - Valid bool `json:"valid"` -} - -// UserInviteRegenerateRequest Request to regenerate an invite link -type UserInviteRegenerateRequest struct { - // ExpiresIn Invite expiration time in seconds (default 72 hours) - ExpiresIn *int `json:"expires_in,omitempty"` -} - -// UserInviteRegenerateResponse Response after regenerating an invite -type UserInviteRegenerateResponse struct { - // InviteExpiresAt New invite expiration time - InviteExpiresAt time.Time `json:"invite_expires_at"` - - // InviteToken The new invite token - InviteToken string `json:"invite_token"` -} - // UserPermissions defines model for UserPermissions. type UserPermissions struct { // IsRestricted Indicates whether this User's Peers view is restricted @@ -2297,20 +2209,6 @@ type UserRequest struct { Role string `json:"role"` } -// WorkloadRequest defines model for WorkloadRequest. -type WorkloadRequest struct { - union json.RawMessage -} - -// WorkloadResponse defines model for WorkloadResponse. -type WorkloadResponse struct { - union json.RawMessage -} - -// WorkloadType Identifies the type of workload the job will execute. -// Currently only `"bundle"` is supported. -type WorkloadType string - // Zone defines model for Zone. type Zone struct { // DistributionGroups Group IDs that defines groups of peers that will resolve this zone @@ -2494,9 +2392,6 @@ type PostApiPeersPeerIdIngressPortsJSONRequestBody = IngressPortAllocationReques // PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody defines body for PutApiPeersPeerIdIngressPortsAllocationId for application/json ContentType. type PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody = IngressPortAllocationRequest -// PostApiPeersPeerIdJobsJSONRequestBody defines body for PostApiPeersPeerIdJobs for application/json ContentType. -type PostApiPeersPeerIdJobsJSONRequestBody = JobRequest - // PostApiPeersPeerIdTemporaryAccessJSONRequestBody defines body for PostApiPeersPeerIdTemporaryAccess for application/json ContentType. type PostApiPeersPeerIdTemporaryAccessJSONRequestBody = PeerTemporaryAccessRequest @@ -2512,6 +2407,15 @@ type PostApiPostureChecksJSONRequestBody = PostureCheckUpdate // PutApiPostureChecksPostureCheckIdJSONRequestBody defines body for PutApiPostureChecksPostureCheckId for application/json ContentType. type PutApiPostureChecksPostureCheckIdJSONRequestBody = PostureCheckUpdate +// PostApiReverseProxyJSONRequestBody defines body for PostApiReverseProxy for application/json ContentType. +type PostApiReverseProxyJSONRequestBody = ReverseProxyRequest + +// PostApiReverseProxyDomainsJSONRequestBody defines body for PostApiReverseProxyDomains for application/json ContentType. +type PostApiReverseProxyDomainsJSONRequestBody = ReverseProxyDomainRequest + +// PutApiReverseProxyProxyIdJSONRequestBody defines body for PutApiReverseProxyProxyId for application/json ContentType. +type PutApiReverseProxyProxyIdJSONRequestBody = ReverseProxyRequest + // PostApiRoutesJSONRequestBody defines body for PostApiRoutes for application/json ContentType. type PostApiRoutesJSONRequestBody = RouteRequest @@ -2530,138 +2434,8 @@ type PutApiSetupKeysKeyIdJSONRequestBody = SetupKeyRequest // PostApiUsersJSONRequestBody defines body for PostApiUsers for application/json ContentType. type PostApiUsersJSONRequestBody = UserCreateRequest -// PostApiUsersInvitesJSONRequestBody defines body for PostApiUsersInvites for application/json ContentType. -type PostApiUsersInvitesJSONRequestBody = UserInviteCreateRequest - -// PostApiUsersInvitesInviteIdRegenerateJSONRequestBody defines body for PostApiUsersInvitesInviteIdRegenerate for application/json ContentType. -type PostApiUsersInvitesInviteIdRegenerateJSONRequestBody = UserInviteRegenerateRequest - -// PostApiUsersInvitesTokenAcceptJSONRequestBody defines body for PostApiUsersInvitesTokenAccept for application/json ContentType. -type PostApiUsersInvitesTokenAcceptJSONRequestBody = UserInviteAcceptRequest - // PutApiUsersUserIdJSONRequestBody defines body for PutApiUsersUserId for application/json ContentType. type PutApiUsersUserIdJSONRequestBody = UserRequest -// PutApiUsersUserIdPasswordJSONRequestBody defines body for PutApiUsersUserIdPassword for application/json ContentType. -type PutApiUsersUserIdPasswordJSONRequestBody = PasswordChangeRequest - // PostApiUsersUserIdTokensJSONRequestBody defines body for PostApiUsersUserIdTokens for application/json ContentType. type PostApiUsersUserIdTokensJSONRequestBody = PersonalAccessTokenRequest - -// AsBundleWorkloadRequest returns the union data inside the WorkloadRequest as a BundleWorkloadRequest -func (t WorkloadRequest) AsBundleWorkloadRequest() (BundleWorkloadRequest, error) { - var body BundleWorkloadRequest - err := json.Unmarshal(t.union, &body) - return body, err -} - -// FromBundleWorkloadRequest overwrites any union data inside the WorkloadRequest as the provided BundleWorkloadRequest -func (t *WorkloadRequest) FromBundleWorkloadRequest(v BundleWorkloadRequest) error { - v.Type = "bundle" - b, err := json.Marshal(v) - t.union = b - return err -} - -// MergeBundleWorkloadRequest performs a merge with any union data inside the WorkloadRequest, using the provided BundleWorkloadRequest -func (t *WorkloadRequest) MergeBundleWorkloadRequest(v BundleWorkloadRequest) error { - v.Type = "bundle" - b, err := json.Marshal(v) - if err != nil { - return err - } - - merged, err := runtime.JSONMerge(t.union, b) - t.union = merged - return err -} - -func (t WorkloadRequest) Discriminator() (string, error) { - var discriminator struct { - Discriminator string `json:"type"` - } - err := json.Unmarshal(t.union, &discriminator) - return discriminator.Discriminator, err -} - -func (t WorkloadRequest) ValueByDiscriminator() (interface{}, error) { - discriminator, err := t.Discriminator() - if err != nil { - return nil, err - } - switch discriminator { - case "bundle": - return t.AsBundleWorkloadRequest() - default: - return nil, errors.New("unknown discriminator value: " + discriminator) - } -} - -func (t WorkloadRequest) MarshalJSON() ([]byte, error) { - b, err := t.union.MarshalJSON() - return b, err -} - -func (t *WorkloadRequest) UnmarshalJSON(b []byte) error { - err := t.union.UnmarshalJSON(b) - return err -} - -// AsBundleWorkloadResponse returns the union data inside the WorkloadResponse as a BundleWorkloadResponse -func (t WorkloadResponse) AsBundleWorkloadResponse() (BundleWorkloadResponse, error) { - var body BundleWorkloadResponse - err := json.Unmarshal(t.union, &body) - return body, err -} - -// FromBundleWorkloadResponse overwrites any union data inside the WorkloadResponse as the provided BundleWorkloadResponse -func (t *WorkloadResponse) FromBundleWorkloadResponse(v BundleWorkloadResponse) error { - v.Type = "bundle" - b, err := json.Marshal(v) - t.union = b - return err -} - -// MergeBundleWorkloadResponse performs a merge with any union data inside the WorkloadResponse, using the provided BundleWorkloadResponse -func (t *WorkloadResponse) MergeBundleWorkloadResponse(v BundleWorkloadResponse) error { - v.Type = "bundle" - b, err := json.Marshal(v) - if err != nil { - return err - } - - merged, err := runtime.JSONMerge(t.union, b) - t.union = merged - return err -} - -func (t WorkloadResponse) Discriminator() (string, error) { - var discriminator struct { - Discriminator string `json:"type"` - } - err := json.Unmarshal(t.union, &discriminator) - return discriminator.Discriminator, err -} - -func (t WorkloadResponse) ValueByDiscriminator() (interface{}, error) { - discriminator, err := t.Discriminator() - if err != nil { - return nil, err - } - switch discriminator { - case "bundle": - return t.AsBundleWorkloadResponse() - default: - return nil, errors.New("unknown discriminator value: " + discriminator) - } -} - -func (t WorkloadResponse) MarshalJSON() ([]byte, error) { - b, err := t.union.MarshalJSON() - return b, err -} - -func (t *WorkloadResponse) UnmarshalJSON(b []byte) error { - err := t.union.UnmarshalJSON(b) - return err -}