* New Docs

CSS update and Dockerfile to include docs folder

flash of unrendered text fix

markdown docs

ignore docs/docs.go

improving the docs generation

github actions for docs generation

go runner version fix

updated docs.yml

update repo action updated

updated actions and dns docs

dns complete

More docs update

Complete docs and updated workflow

Update documentation Tue Aug  6 11:17:42 UTC 2024

Update documentation Thu Aug  8 12:26:57 UTC 2024

clean up

clean up

Dockerfile clean up

Updated workflow

Updated workflow

Update docs.yml

Update docs.yml

* requested changes

* changed ingress gateway to remote access gateway
This commit is contained in:
Sayan Mallick
2024-08-15 11:55:01 +05:30
committed by GitHub
parent 7786c106f7
commit c551c487ca
25 changed files with 4916 additions and 4688 deletions

50
.github/workflows/docs.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: Generate Documentation
on:
workflow_dispatch:
inputs:
branch:
description: 'Branch to run the workflow against'
required: true
default: 'master'
jobs:
generate-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: gravitl/netmaker
ref: ${{ github.event.inputs.branch || 'master' }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Install Swag
run: go install github.com/swaggo/swag/cmd/swag@latest
- name: Generating Docs
run: |
export PATH=$PATH:$(go env GOPATH)/bin
swag i --md docs/ --parseDependency --parseInternal --outputTypes yaml --parseDepth 1 --output .
- name: Get current timestamp
id: timestamp
run: echo "timestamp=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Update documentation ${{ steps.timestamp.outputs.timestamp }}"
title: "Update Swagger documentation ${{ steps.timestamp.outputs.timestamp }}"
body: |
This PR updates the swagger.yml file with the latest documentation changes.
Updated on: ${{ steps.timestamp.outputs.timestamp }}
branch: update-swagger-docs-${{ github.event.inputs.branch }}
base: ${{ github.event.inputs.branch }}
delete-branch: true

View File

@@ -35,7 +35,6 @@ var HttpHandlers = []interface{}{
legacyHandlers, legacyHandlers,
} }
// HandleRESTRequests - handles the rest requests
func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) { func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) {
defer wg.Done() defer wg.Done()
@@ -43,9 +42,19 @@ func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) {
// Currently allowed dev origin is all. Should change in prod // Currently allowed dev origin is all. Should change in prod
// should consider analyzing the allowed methods further // should consider analyzing the allowed methods further
headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization", "From-Ui"}) headersOk := handlers.AllowedHeaders(
[]string{
"Access-Control-Allow-Origin",
"X-Requested-With",
"Content-Type",
"authorization",
"From-Ui",
},
)
originsOk := handlers.AllowedOrigins(strings.Split(servercfg.GetAllowedOrigin(), ",")) originsOk := handlers.AllowedOrigins(strings.Split(servercfg.GetAllowedOrigin(), ","))
methodsOk := handlers.AllowedMethods([]string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete}) methodsOk := handlers.AllowedMethods(
[]string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
)
for _, middleware := range HttpMiddlewares { for _, middleware := range HttpMiddlewares {
r.Use(middleware) r.Use(middleware)
@@ -57,7 +66,10 @@ func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) {
port := servercfg.GetAPIPort() port := servercfg.GetAPIPort()
srv := &http.Server{Addr: ":" + port, Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r)} srv := &http.Server{
Addr: ":" + port,
Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r),
}
go func() { go func() {
err := srv.ListenAndServe() err := srv.ListenAndServe()
if err != nil { if err != nil {

View File

@@ -16,25 +16,29 @@ import (
func dnsHandlers(r *mux.Router) { func dnsHandlers(r *mux.Router) {
r.HandleFunc("/api/dns", logic.SecurityCheck(true, http.HandlerFunc(getAllDNS))).Methods(http.MethodGet) r.HandleFunc("/api/dns", logic.SecurityCheck(true, http.HandlerFunc(getAllDNS))).
r.HandleFunc("/api/dns/adm/{network}/nodes", logic.SecurityCheck(true, http.HandlerFunc(getNodeDNS))).Methods(http.MethodGet) Methods(http.MethodGet)
r.HandleFunc("/api/dns/adm/{network}/custom", logic.SecurityCheck(true, http.HandlerFunc(getCustomDNS))).Methods(http.MethodGet) r.HandleFunc("/api/dns/adm/{network}/nodes", logic.SecurityCheck(true, http.HandlerFunc(getNodeDNS))).
r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(true, http.HandlerFunc(getDNS))).Methods(http.MethodGet) Methods(http.MethodGet)
r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(true, http.HandlerFunc(createDNS))).Methods(http.MethodPost) r.HandleFunc("/api/dns/adm/{network}/custom", logic.SecurityCheck(true, http.HandlerFunc(getCustomDNS))).
r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(true, http.HandlerFunc(pushDNS))).Methods(http.MethodPost) Methods(http.MethodGet)
r.HandleFunc("/api/dns/{network}/{domain}", logic.SecurityCheck(true, http.HandlerFunc(deleteDNS))).Methods(http.MethodDelete) r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(true, http.HandlerFunc(getDNS))).
Methods(http.MethodGet)
r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(true, http.HandlerFunc(createDNS))).
Methods(http.MethodPost)
r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(true, http.HandlerFunc(pushDNS))).
Methods(http.MethodPost)
r.HandleFunc("/api/dns/{network}/{domain}", logic.SecurityCheck(true, http.HandlerFunc(deleteDNS))).
Methods(http.MethodDelete)
} }
// swagger:route GET /api/dns/adm/{network}/nodes dns getNodeDNS // @Summary Gets node DNS entries associated with a network
// // @Router /api/dns/{network} [get]
// Gets node DNS entries associated with a network. // @Tags DNS
// // @Accept json
// Schemes: https // @Param network path string true "Network identifier"
// // @Success 200 {array} models.DNSEntry
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
// Responses:
// 200: dnsResponse
func getNodeDNS(w http.ResponseWriter, r *http.Request) { func getNodeDNS(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -53,17 +57,12 @@ func getNodeDNS(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(dns) json.NewEncoder(w).Encode(dns)
} }
// swagger:route GET /api/dns dns getAllDNS // @Summary Get all DNS entries
// // @Router /api/dns [get]
// Gets all DNS entries. // @Tags DNS
// // @Accept json
// Schemes: https // @Success 200 {array} models.DNSEntry
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: dnsResponse
func getAllDNS(w http.ResponseWriter, r *http.Request) { func getAllDNS(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
dns, err := logic.GetAllDNS() dns, err := logic.GetAllDNS()
@@ -77,17 +76,13 @@ func getAllDNS(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(dns) json.NewEncoder(w).Encode(dns)
} }
// swagger:route GET /api/dns/adm/{network}/custom dns getCustomDNS // @Summary Gets custom DNS entries associated with a network
// // @Router /api/dns/adm/{network}/custom [get]
// Gets custom DNS entries associated with a network. // @Tags DNS
// // @Accept json
// Schemes: https // @Param network path string true "Network identifier"
// // @Success 200 {array} models.DNSEntry
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: dnsResponse
func getCustomDNS(w http.ResponseWriter, r *http.Request) { func getCustomDNS(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -97,8 +92,15 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
network := params["network"] network := params["network"]
dns, err := logic.GetCustomDNS(network) dns, err := logic.GetCustomDNS(network)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(
fmt.Sprintf("failed to get custom DNS entries for network [%s]: %v", network, err.Error())) 0,
r.Header.Get("user"),
fmt.Sprintf(
"failed to get custom DNS entries for network [%s]: %v",
network,
err.Error(),
),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -106,17 +108,13 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(dns) json.NewEncoder(w).Encode(dns)
} }
// swagger:route GET /api/dns/adm/{network} dns getDNS // @Summary Get all DNS entries associated with the network
// // @Router /api/dns/adm/{network} [get]
// Gets all DNS entries associated with the network. // @Tags DNS
// // @Accept json
// Schemes: https // @Param network path string true "Network identifier"
// // @Success 200 {array} models.DNSEntry
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: dnsResponse
func getDNS(w http.ResponseWriter, r *http.Request) { func getDNS(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -135,17 +133,15 @@ func getDNS(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(dns) json.NewEncoder(w).Encode(dns)
} }
// swagger:route POST /api/dns/{network} dns createDNS // @Summary Create a new DNS entry
// // @Router /api/dns/adm/{network} [post]
// Create a DNS entry. // @Tags DNS
// // @Accept json
// Schemes: https // @Param network path string true "Network identifier"
// // @Param body body models.DNSEntry true "DNS entry details"
// Security: // @Success 200 {object} models.DNSEntry
// oauth // @Failure 400 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: dnsResponse
func createDNS(w http.ResponseWriter, r *http.Request) { func createDNS(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -187,18 +183,14 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(entry) json.NewEncoder(w).Encode(entry)
} }
// swagger:route DELETE /api/dns/{network}/{domain} dns deleteDNS // @Summary Delete a DNS entry
// // @Router /api/dns/{network}/{domain} [delete]
// Delete a DNS entry. // @Tags DNS
// // @Accept json
// Schemes: https // @Param network path string true "Network identifier"
// // @Param domain path string true "Domain Name"
// Security: // @Success 200 {array} models.DNSEntry
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: stringJSONResponse
// *: stringJSONResponse
func deleteDNS(w http.ResponseWriter, r *http.Request) { func deleteDNS(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -243,23 +235,22 @@ func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
return entry, err return entry, err
} }
// swagger:route POST /api/dns/adm/pushdns dns pushDNS // @Summary Push DNS entries to nameserver
// // @Router /api/dns/adm/pushdns [post]
// Push DNS entries to nameserver. // @Tags DNS
// // @Accept json
// Schemes: https // @Success 200 {string} string "DNS Pushed to CoreDNS"
// // @Failure 400 {object} models.ErrorResponse
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: dnsResponse
// *: dnsResponse
func pushDNS(w http.ResponseWriter, r *http.Request) { func pushDNS(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if !servercfg.IsDNSMode() { if !servercfg.IsDNSMode() {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("DNS Mode is set to off"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("DNS Mode is set to off"), "badrequest"),
)
return return
} }
err := logic.SetDNS() err := logic.SetDNS()

View File

@@ -1,475 +0,0 @@
// Package classification Netmaker
//
// # API Usage
//
// Most actions that can be performed via API can be performed via UI. We recommend managing your networks using the official netmaker-ui project. However, Netmaker can also be run without the UI, and all functions can be achieved via API calls. If your use case requires using Netmaker without the UI or you need to do some troubleshooting/advanced configuration, using the API directly may help.
//
// # Authentication
//
// API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
//
// Schemes: https
// BasePath: /
// Version: 0.25.0
// Host: api.demo.netmaker.io
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Security:
// - oauth
//
// swagger:meta
package controller
import (
"os"
"github.com/gravitl/netmaker/config"
"github.com/gravitl/netmaker/logic/acls"
"github.com/gravitl/netmaker/models"
)
var _ = useUnused() // "use" the function to prevent "unused function" errors
// swagger:parameters getFile
type filenameToGet struct {
// Filename
// in: path
// required: true
Filename string `json:"filename"`
}
// swagger:response hasAdmin
type hasAdmin struct {
// in: body
Admin bool
}
// swagger:response apiHostSliceResponse
type apiHostSliceResponse struct {
// in: body
Host []models.ApiHost
}
// swagger:response apiHostResponse
type apiHostResponse struct {
// in: body
Host models.ApiHost
}
// swagger:parameters getNodeDNS getCustomDNS getDNS
type dnsNetworkPathParam struct {
// Network
// in: path
Network string `json:"network"`
}
// swagger:parameters createDNS
type dnsParams struct {
// Network
// in: path
Network string `json:"network"`
// DNS Entry
// in: body
Body []models.DNSEntry `json:"body"`
}
// Success
// swagger:response dnsResponse
type dnsResponse struct {
// in: body
Body []models.DNSEntry `json:"body"`
}
// swagger:parameters deleteDNS
type dnsDeletePathParams struct {
// Network
// in: path
Network string `json:"network"`
// Domain
// in: path
Domain string `json:"domain"`
}
// swagger:response stringJSONResponse
type stringJSONResponse struct {
// Response
// in: body
Response string `json:"response"`
}
//swagger:response EnrollmentKey
type EnrollmentKey struct {
// in: body
EnrollmentKey models.EnrollmentKey
}
//swagger:response EnrollmentKeys
type EnrollmentKeys struct {
// in: body
EnrollmentKeys []models.EnrollmentKey
}
// swagger:parameters getAllExtClients
type getAllClientsRequest struct {
// Networks
// in:body
Networks []string `json:"networks"`
}
// swagger:response extClientSliceResponse
type extClientSliceResponse struct {
// ExtClients
// in: body
ExtClients []models.ExtClient `json:"ext_clients"`
}
// swagger:response extClientResponse
type extClientResponse struct {
// ExtClient
// in: body
ExtClient models.ExtClient `json:"ext_client"`
}
// swagger:response fileResponse
type fileResponse struct {
// in: body
File os.File
}
// swagger:response successResponse
type successResponse struct {
// Success Response
// in: body
SuccessResponse models.SuccessResponse `json:"success_response"`
}
// swagger:parameters getExtClientConf
type extClientConfParams struct {
// Client ID
// in: path
ClientID string `json:"clientid"`
// Network
// in: path
Network string `json:"network"`
// Type
// in: path
Type string `json:"type"`
}
// swagger:parameters getExtClient getExtClientConf updateExtClient deleteExtClient
type extClientPathParams struct {
// Client ID
// in: path
ClientID string `json:"clientid"`
// Network
// in: path
Network string `json:"network"`
}
// swagger:parameters updateExtClient
type extClientBodyParam struct {
// ExtClient
// in: body
ExtClient models.ExtClient `json:"ext_client"`
}
// swagger:parameters getNetworkExtClients
type extClientNetworkPathParam struct {
// Network
// in: path
Network string `json:"network"`
}
// swagger:parameters createExtClient
type createExtClientPathParams struct {
// Network
// in: path
Network string `json:"network"`
// Node ID
// in: path
NodeID string `json:"nodeid"`
// Custom ExtClient
// in: body
CustomExtClient models.CustomExtClient `json:"custom_ext_client"`
}
// swagger:parameters getNode updateNode deleteNode createRelay deleteRelay createEgressGateway deleteEgressGateway createIngressGateway deleteIngressGateway ingressGatewayUsers
type networkNodePathParams struct {
// in: path
Network string `json:"network"`
// in: path
NodeID string `json:"nodeid"`
}
// swagger:response byteArrayResponse
type byteArrayResponse struct {
// in: body
ByteArray []byte `json:"byte_array"`
}
// swagger:parameters getNetwork deleteNetwork updateNetwork getNetworkACL updateNetworkACL
type NetworkParam struct {
// name: network name
// in: path
Networkname string `json:"networkname"`
}
// swagger:response getNetworksSliceResponse
type getNetworksSliceResponse struct {
// Networks
// in: body
Networks []models.Network `json:"networks"`
}
// swagger:response hostPull
type hostPull struct {
// hostPull
// in: body
HostPull models.HostPull
}
// swagger:parameters createNetwork updateNetwork
type networkBodyParam struct {
// Network
// in: body
Network models.Network `json:"network"`
}
// swagger:parameters updateNetworkNodeLimit keyUpdate createAccessKey getAccessKeys getNetworkNodes
type networkPathParam struct {
// Network
// in: path
Network string `json:"network"`
}
// swagger:response networkBodyResponse
type networkBodyResponse struct {
// Network
// in: body
Network models.Network `json:"network"`
}
// swagger:parameters updateNetworkACL
type aclContainerBodyParam struct {
// ACL Container
// in: body
ACLContainer acls.ACLContainer `json:"acl_container"`
}
// swagger:response aclContainerResponse
type aclContainerResponse struct {
// ACL Container
// in: body
ACLContainer acls.ACLContainer `json:"acl_container"`
}
// swagger:response nodeSliceResponse
type nodeSliceResponse struct {
// Nodes
// in: body
Nodes []models.ApiNode `json:"nodes"`
}
// swagger:response nodeResponse
type nodeResponse struct {
// Node
// in: body
Node models.LegacyNode `json:"node"`
}
// swagger:parameters updateNode deleteNode
type nodeBodyParam struct {
// Node
// in: body
Node models.LegacyNode `json:"node"`
}
//swagger:response okResponse
type okRespone struct{}
// swagger:response RegisterResponse
type RegisterResponse struct {
// in: body
RegisterResponse models.RegisterResponse
}
// swagger:parameters createRelay
type relayRequestBodyParam struct {
// Relay Request
// in: body
RelayRequest models.RelayRequest `json:"relay_request"`
}
// swagger:parameters createEgressGateway
type egressGatewayBodyParam struct {
// Egress Gateway Request
// in: body
EgressGatewayRequest models.EgressGatewayRequest `json:"egress_gateway_request"`
}
// swagger:parameters attachUserToRemoteAccessGateway removeUserFromRemoteAccessGW getUserRemoteAccessGws
type RemoteAccessGatewayUser struct {
// in: path
Username string `json:"username"`
}
// swagger:parameters authenticate
type authParamBodyParam struct {
// network
// in: path
Network string `json:"network"`
// AuthParams
// in: body
AuthParams models.AuthParams `json:"auth_params"`
}
// swagger:response signal
type signal struct {
// in: body
Signal models.Signal
}
// swagger:parameters synchost deleteHost updateHost signalPeer updateKeys
type HostID struct {
// HostID
// in: path
HostID string `json:"hostid"`
}
// swagger:parameters addHostToNetwork deleteHostFromNetwork
type HostFromNetworkParams struct {
// hostid to add or delete from network
// in: path
HostID string `json:"hostid"`
// network
// in: path
Network string `json:"network"`
}
// swagger:parameters createEnrollmentKey
type createEnrollmentKeyParams struct {
// APIEnrollmentKey
// in: body
Body models.APIEnrollmentKey `json:"body"`
}
// swagger:parameters updateEnrollmentKey
type updateEnrollmentKeyParams struct {
// KeyID
// in: path
KeyID string `json:"keyid"`
// APIEnrollmentKey
// in: body
Body models.APIEnrollmentKey `json:"body"`
}
// swagger:parameters deleteEnrollmentKey
type deleteEnrollmentKeyParam struct {
// in: path
KeyID string `json:"keyid"`
}
// swagger:parameters handleHostRegister
type RegisterParams struct {
// in: path
Token string `json:"token"`
// in: body
Host models.Host `json:"host"`
}
// swagger:response serverConfigResponse
type serverConfigResponse struct {
// Server Config
// in: body
// example
//{
//"mqusername": "xxxxxxx"
//}
ServerConfig config.ServerConfig `json:"server_config"`
}
// swagger:parameters createAdmin updateUser updateUserNetworks createUser
type userBodyParam struct {
// User
// in: body
User models.User `json:"user"`
}
// swagger:response userBodyResponse
type userBodyResponse struct {
// User
// in: body
User models.User `json:"user"`
}
// swagger:parameters authenticateUser
type userAuthBodyParam struct {
// User Auth Params
// in: body
UserAuthParams models.UserAuthParams `json:"user_auth_params"`
}
// swagger:parameters updateUser updateUserNetworks updateUserAdm createUser deleteUser getUser
type usernamePathParam struct {
// Username
// in: path
Username string `json:"username"`
}
// prevent issues with integration tests for types just used by Swagger docs.
func useUnused() bool {
_ = dnsParams{}
_ = dnsResponse{}
_ = dnsDeletePathParams{}
_ = stringJSONResponse{}
_ = getAllClientsRequest{}
_ = extClientSliceResponse{}
_ = extClientResponse{}
_ = successResponse{}
_ = extClientPathParams{}
_ = extClientBodyParam{}
_ = extClientNetworkPathParam{}
_ = createExtClientPathParams{}
_ = networkNodePathParams{}
_ = byteArrayResponse{}
_ = getNetworksSliceResponse{}
_ = networkBodyParam{}
_ = networkPathParam{}
_ = networkBodyResponse{}
_ = aclContainerBodyParam{}
_ = aclContainerResponse{}
_ = nodeSliceResponse{}
_ = nodeResponse{}
_ = nodeBodyParam{}
_ = relayRequestBodyParam{}
_ = egressGatewayBodyParam{}
_ = authParamBodyParam{}
_ = serverConfigResponse{}
_ = userBodyParam{}
_ = userBodyResponse{}
_ = userAuthBodyParam{}
_ = usernamePathParam{}
_ = hasAdmin{}
_ = apiHostSliceResponse{}
_ = apiHostResponse{}
_ = fileResponse{}
_ = extClientConfParams{}
_ = hostPull{}
_ = okRespone{}
_ = signal{}
_ = filenameToGet{}
_ = dnsNetworkPathParam{}
_ = createEnrollmentKeyParams{}
_ = updateEnrollmentKeyParams{}
_ = deleteEnrollmentKeyParam{}
return false
}

View File

@@ -32,17 +32,12 @@ func enrollmentKeyHandlers(r *mux.Router) {
Methods(http.MethodPut) Methods(http.MethodPut)
} }
// swagger:route GET /api/v1/enrollment-keys enrollmentKeys getEnrollmentKeys // @Summary Lists all EnrollmentKeys for admins
// // @Router /api/v1/enrollment-keys [get]
// Lists all EnrollmentKeys for admins. // @Tags EnrollmentKeys
// // @Security oauth
// Schemes: https // @Success 200 {array} models.EnrollmentKey
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: EnrollmentKeys
func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) { func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) {
keys, err := logic.GetAllEnrollmentKeys() keys, err := logic.GetAllEnrollmentKeys()
if err != nil { if err != nil {
@@ -67,17 +62,13 @@ func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(ret) json.NewEncoder(w).Encode(ret)
} }
// swagger:route DELETE /api/v1/enrollment-keys/{keyid} enrollmentKeys deleteEnrollmentKey // @Summary Deletes an EnrollmentKey from Netmaker server
// // @Router /api/v1/enrollment-keys/{keyid} [delete]
// Deletes an EnrollmentKey from Netmaker server. // @Tags EnrollmentKeys
// // @Security oauth
// Schemes: https // @Param keyid path string true "Enrollment Key ID"
// // @Success 200
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: okResponse
func deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) { func deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r) params := mux.Vars(r)
keyID := params["keyID"] keyID := params["keyID"]
@@ -91,17 +82,14 @@ func deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route POST /api/v1/enrollment-keys enrollmentKeys createEnrollmentKey // @Summary Creates an EnrollmentKey for hosts to register with server and join networks
// // @Router /api/v1/enrollment-keys [post]
// Creates an EnrollmentKey for hosts to use on Netmaker server. // @Tags EnrollmentKeys
// // @Security oauth
// Schemes: https // @Param body body models.APIEnrollmentKey true "Enrollment Key parameters"
// // @Success 200 {object} models.EnrollmentKey
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: EnrollmentKey
func createEnrollmentKey(w http.ResponseWriter, r *http.Request) { func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
var enrollmentKeyBody models.APIEnrollmentKey var enrollmentKeyBody models.APIEnrollmentKey
@@ -121,7 +109,14 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), "error validating request body: ", logger.Log(0, r.Header.Get("user"), "error validating request body: ",
err.Error()) err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("validation error: name length must be between 3 and 32: %w", err), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("validation error: name length must be between 3 and 32: %w", err),
"badrequest",
),
)
return return
} }
@@ -180,17 +175,15 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(newEnrollmentKey) json.NewEncoder(w).Encode(newEnrollmentKey)
} }
// swagger:route PUT /api/v1/enrollment-keys/{keyid} enrollmentKeys updateEnrollmentKey // @Summary Updates an EnrollmentKey. Updates are only limited to the relay to use
// // @Router /api/v1/enrollment-keys/{keyid} [put]
// Updates an EnrollmentKey for hosts to use on Netmaker server. Updates only the relay to use. // @Tags EnrollmentKeys
// // @Security oauth
// Schemes: https // @Param keyid path string true "Enrollment Key ID"
// // @Param body body models.APIEnrollmentKey true "Enrollment Key parameters"
// Security: // @Success 200 {object} models.EnrollmentKey
// oauth // @Failure 400 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: EnrollmentKey
func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) { func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) {
var enrollmentKeyBody models.APIEnrollmentKey var enrollmentKeyBody models.APIEnrollmentKey
params := mux.Vars(r) params := mux.Vars(r)
@@ -231,17 +224,15 @@ func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(newEnrollmentKey) json.NewEncoder(w).Encode(newEnrollmentKey)
} }
// swagger:route POST /api/v1/enrollment-keys/{token} enrollmentKeys handleHostRegister // @Summary Handles a Netclient registration with server and add nodes accordingly
// // @Router /api/v1/host/register/{token} [post]
// Handles a Netclient registration with server and add nodes accordingly. // @Tags EnrollmentKeys
// // @Security oauth
// Schemes: https // @Param token path string true "Enrollment Key Token"
// // @Param body body models.Host true "Host registration parameters"
// Security: // @Success 200 {object} models.RegisterResponse
// oauth // @Failure 400 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: RegisterResponse
func handleHostRegister(w http.ResponseWriter, r *http.Request) { func handleHostRegister(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r) params := mux.Vars(r)
token := params["token"] token := params["token"]

View File

@@ -28,13 +28,20 @@ import (
func extClientHandlers(r *mux.Router) { func extClientHandlers(r *mux.Router) {
r.HandleFunc("/api/extclients", logic.SecurityCheck(true, http.HandlerFunc(getAllExtClients))).Methods(http.MethodGet) r.HandleFunc("/api/extclients", logic.SecurityCheck(true, http.HandlerFunc(getAllExtClients))).
r.HandleFunc("/api/extclients/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkExtClients))).Methods(http.MethodGet) Methods(http.MethodGet)
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(getExtClient))).Methods(http.MethodGet) r.HandleFunc("/api/extclients/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkExtClients))).
r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.SecurityCheck(false, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet) Methods(http.MethodGet)
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut) r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(getExtClient))).
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete) Methods(http.MethodGet)
r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost) r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.SecurityCheck(false, http.HandlerFunc(getExtClientConf))).
Methods(http.MethodGet)
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(updateExtClient))).
Methods(http.MethodPut)
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(deleteExtClient))).
Methods(http.MethodDelete)
r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).
Methods(http.MethodPost)
} }
func checkIngressExists(nodeID string) bool { func checkIngressExists(nodeID string) bool {
@@ -45,18 +52,12 @@ func checkIngressExists(nodeID string) bool {
return node.IsIngressGateway return node.IsIngressGateway
} }
// swagger:route GET /api/extclients/{network} ext_client getNetworkExtClients // @Summary Get all remote access client associated with network
// // @Router /api/extclients/{network} [get]
// Get all extclients associated with network. // @Tags Remote Access Client
// Gets all extclients associated with network, including pending extclients. // @Security oauth2
// // @Success 200 {object} models.ExtClient
// Schemes: https // @Failure 500 {object} models.ErrorResponse
//
// Security:
// oauth
//
// Responses:
// 200: extClientSliceResponse
func getNetworkExtClients(w http.ResponseWriter, r *http.Request) { func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -77,18 +78,12 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(extclients) json.NewEncoder(w).Encode(extclients)
} }
// swagger:route GET /api/extclients ext_client getAllExtClients // @Summary Fetches All Remote Access Clients across all networks
// // @Router /api/extclients [get]
// A separate function to get all extclients, not just extclients for a particular network. // @Tags Remote Access Client
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ExtClient
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: extClientSliceResponse
//
// Not quite sure if this is necessary. Probably necessary based on front end but may // Not quite sure if this is necessary. Probably necessary based on front end but may
// want to review after iteration 1 if it's being used or not // want to review after iteration 1 if it's being used or not
func getAllExtClients(w http.ResponseWriter, r *http.Request) { func getAllExtClients(w http.ResponseWriter, r *http.Request) {
@@ -107,17 +102,13 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(clients) json.NewEncoder(w).Encode(clients)
} }
// swagger:route GET /api/extclients/{network}/{clientid} ext_client getExtClient // @Summary Get an individual remote access client
// // @Router /api/extclients/{network}/{clientid} [get]
// Get an individual extclient. // @Tags Remote Access Client
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ExtClient
// // @Failure 500 {object} models.ErrorResponse
// Security: // @Failure 403 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: extClientResponse
func getExtClient(w http.ResponseWriter, r *http.Request) { func getExtClient(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -128,8 +119,12 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
network := params["network"] network := params["network"]
client, err := logic.GetExtClient(clientid, network) client, err := logic.GetExtClient(clientid, network)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v", logger.Log(
clientid, network, err)) 0,
r.Header.Get("user"),
fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
clientid, network, err),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -137,7 +132,11 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
// check if user has access to extclient // check if user has access to extclient
slog.Error("failed to get extclient", "network", network, "clientID", slog.Error("failed to get extclient", "network", network, "clientID",
clientid, "error", errors.New("access is denied")) clientid, "error", errors.New("access is denied"))
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("access is denied"), "forbidden"),
)
return return
} }
@@ -146,17 +145,13 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(client) json.NewEncoder(w).Encode(client)
} }
// swagger:route GET /api/extclients/{network}/{clientid}/{type} ext_client getExtClientConf // @Summary Get an individual remote access client
// // @Router /api/extclients/{network}/{clientid}/{type} [get]
// Get an individual extclient. // @Tags Remote Access Client
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ExtClient
// // @Failure 500 {object} models.ErrorResponse
// Security: // @Failure 403 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: extClientResponse
func getExtClientConf(w http.ResponseWriter, r *http.Request) { func getExtClientConf(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -166,36 +161,63 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
networkid := params["network"] networkid := params["network"]
client, err := logic.GetExtClient(clientid, networkid) client, err := logic.GetExtClient(clientid, networkid)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v", logger.Log(
clientid, networkid, err)) 0,
r.Header.Get("user"),
fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
clientid, networkid, err),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) { if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
slog.Error("failed to get extclient", "network", networkid, "clientID", slog.Error("failed to get extclient", "network", networkid, "clientID",
clientid, "error", errors.New("access is denied")) clientid, "error", errors.New("access is denied"))
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("access is denied"), "forbidden"),
)
return return
} }
gwnode, err := logic.GetNodeByID(client.IngressGatewayID) gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(
fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", client.IngressGatewayID, err)) 0,
r.Header.Get("user"),
fmt.Sprintf(
"failed to get ingress gateway node [%s] info: %v",
client.IngressGatewayID,
err,
),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
host, err := logic.GetHost(gwnode.HostID.String()) host, err := logic.GetHost(gwnode.HostID.String())
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(
fmt.Sprintf("failed to get host for ingress gateway node [%s] info: %v", client.IngressGatewayID, err)) 0,
r.Header.Get("user"),
fmt.Sprintf(
"failed to get host for ingress gateway node [%s] info: %v",
client.IngressGatewayID,
err,
),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
network, err := logic.GetParentNetwork(client.Network) network, err := logic.GetParentNetwork(client.Network)
if err != nil { if err != nil {
logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Network", client.Network) logger.Log(
1,
r.Header.Get("user"),
"Could not retrieve Ingress Gateway Network",
client.Network,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -209,8 +231,19 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
allowedPreferredIps = append(allowedPreferredIps, host.EndpointIP.String()) allowedPreferredIps = append(allowedPreferredIps, host.EndpointIP.String())
allowedPreferredIps = append(allowedPreferredIps, host.EndpointIPv6.String()) allowedPreferredIps = append(allowedPreferredIps, host.EndpointIPv6.String())
if !slices.Contains(allowedPreferredIps, preferredIp) { if !slices.Contains(allowedPreferredIps, preferredIp) {
slog.Warn("preferred endpoint ip is not associated with the RAG. proceeding with preferred ip", "preferred ip", preferredIp) slog.Warn(
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("preferred endpoint ip is not associated with the RAG"), "badrequest")) "preferred endpoint ip is not associated with the RAG. proceeding with preferred ip",
"preferred ip",
preferredIp,
)
logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("preferred endpoint ip is not associated with the RAG"),
"badrequest",
),
)
return return
} }
if net.ParseIP(preferredIp).To4() == nil { if net.ParseIP(preferredIp).To4() == nil {
@@ -354,16 +387,14 @@ Endpoint = %s
json.NewEncoder(w).Encode(client) json.NewEncoder(w).Encode(client)
} }
// swagger:route POST /api/extclients/{network}/{nodeid} ext_client createExtClient // @Summary Create an individual remote access client
// // @Router /api/extclients/{network}/{nodeid} [post]
// Create an individual extclient. Must have valid key and be unique. // @Tags Remote Access Client
// // @Security oauth2
// Schemes: https // @Success 200 {string} string "OK"
// // @Failure 500 {object} models.ErrorResponse
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 403 {object} models.ErrorResponse
// Responses:
// 200: okResponse
func createExtClient(w http.ResponseWriter, r *http.Request) { func createExtClient(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -466,16 +497,40 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
} }
if err = logic.CreateExtClient(&extclient); err != nil { if err = logic.CreateExtClient(&extclient); err != nil {
slog.Error("failed to create extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err) slog.Error(
"failed to create extclient",
"user",
r.Header.Get("user"),
"network",
node.Network,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID) slog.Info(
"created extclient",
"user",
r.Header.Get("user"),
"network",
node.Network,
"clientid",
extclient.ClientID,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
go func() { go func() {
if err := logic.SetClientDefaultACLs(&extclient); err != nil { if err := logic.SetClientDefaultACLs(&extclient); err != nil {
slog.Error("failed to set default acls for extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err) slog.Error(
"failed to set default acls for extclient",
"user",
r.Header.Get("user"),
"network",
node.Network,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -488,17 +543,14 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
}() }()
} }
// swagger:route PUT /api/extclients/{network}/{clientid} ext_client updateExtClient // @Summary Update an individual remote access client
// // @Router /api/extclients/{network}/{clientid} [put]
// Update an individual extclient. // @Tags Remote Access Client
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ExtClient
// // @Failure 500 {object} models.ErrorResponse
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 403 {object} models.ErrorResponse
//
// Responses:
// 200: extClientResponse
func updateExtClient(w http.ResponseWriter, r *http.Request) { func updateExtClient(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -518,7 +570,15 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
network := params["network"] network := params["network"]
oldExtClient, err := logic.GetExtClientByName(clientid) oldExtClient, err := logic.GetExtClientByName(clientid)
if err != nil { if err != nil {
slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err) slog.Error(
"failed to retrieve extclient",
"user",
r.Header.Get("user"),
"id",
clientid,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -526,7 +586,11 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
// check if user has access to extclient // check if user has access to extclient
slog.Error("failed to get extclient", "network", network, "clientID", slog.Error("failed to get extclient", "network", network, "clientID",
clientid, "error", errors.New("access is denied")) clientid, "error", errors.New("access is denied"))
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("access is denied"), "forbidden"),
)
return return
} }
@@ -567,12 +631,32 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
} }
newclient := logic.UpdateExtClient(&oldExtClient, &update) newclient := logic.UpdateExtClient(&oldExtClient, &update)
if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil { if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil {
slog.Error("failed to delete ext client", "user", r.Header.Get("user"), "id", oldExtClient.ClientID, "network", oldExtClient.Network, "error", err) slog.Error(
"failed to delete ext client",
"user",
r.Header.Get("user"),
"id",
oldExtClient.ClientID,
"network",
oldExtClient.Network,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
if err := logic.SaveExtClient(&newclient); err != nil { if err := logic.SaveExtClient(&newclient); err != nil {
slog.Error("failed to save ext client", "user", r.Header.Get("user"), "id", newclient.ClientID, "network", newclient.Network, "error", err) slog.Error(
"failed to save ext client",
"user",
r.Header.Get("user"),
"id",
newclient.ClientID,
"network",
newclient.Network,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -588,13 +672,25 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID) ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID)
if err == nil { if err == nil {
if err = mq.PublishPeerUpdate(false); err != nil { if err = mq.PublishPeerUpdate(false); err != nil {
logger.Log(1, "error setting ext peers on", ingressNode.ID.String(), ":", err.Error()) logger.Log(
1,
"error setting ext peers on",
ingressNode.ID.String(),
":",
err.Error(),
)
} }
} }
if !update.Enabled { if !update.Enabled {
ingressHost, err := logic.GetHost(ingressNode.HostID.String()) ingressHost, err := logic.GetHost(ingressNode.HostID.String())
if err != nil { if err != nil {
slog.Error("Failed to get ingress host", "node", ingressNode.ID.String(), "error", err) slog.Error(
"Failed to get ingress host",
"node",
ingressNode.ID.String(),
"error",
err,
)
return return
} }
nodes, err := logic.GetAllNodes() nodes, err := logic.GetAllNodes()
@@ -602,7 +698,13 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
slog.Error("Failed to get nodes", "error", err) slog.Error("Failed to get nodes", "error", err)
return return
} }
go mq.PublishSingleHostPeerUpdate(ingressHost, nodes, nil, []models.ExtClient{oldExtClient}, false) go mq.PublishSingleHostPeerUpdate(
ingressHost,
nodes,
nil,
[]models.ExtClient{oldExtClient},
false,
)
} }
} }
@@ -610,17 +712,13 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
} }
// swagger:route DELETE /api/extclients/{network}/{clientid} ext_client deleteExtClient // @Summary Delete an individual remote access client
// // @Router /api/extclients/{network}/{clientid} [delete]
// Delete an individual extclient. // @Tags Remote Access Client
// // @Security oauth2
// Schemes: https // @Success 200
// // @Failure 500 {object} models.ErrorResponse
// Security: // @Failure 403 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: successResponse
func deleteExtClient(w http.ResponseWriter, r *http.Request) { func deleteExtClient(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -640,13 +738,24 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) { if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) {
slog.Error("user not allowed to delete", "network", network, "clientID", slog.Error("user not allowed to delete", "network", network, "clientID",
clientid, "error", errors.New("access is denied")) clientid, "error", errors.New("access is denied"))
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("access is denied"), "forbidden"),
)
return return
} }
ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID) ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(
fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err)) 0,
r.Header.Get("user"),
fmt.Sprintf(
"failed to get ingress gateway node [%s] info: %v",
extclient.IngressGatewayID,
err,
),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }

View File

@@ -6,16 +6,12 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
// @Summary Retrieve a file from the file server
// @Router /meshclient/files/{filename} [get]
// @Tags Meshclient
// @Success 200 {body} file "file"
// @Failure 404 {string} string "404 not found"
func fileHandlers(r *mux.Router) { func fileHandlers(r *mux.Router) {
// swagger:route GET /meshclient/files/{filename} meshclient getFile r.PathPrefix("/meshclient/files").
// Handler(http.StripPrefix("/meshclient/files", http.FileServer(http.Dir("./meshclient/files"))))
// Retrieve a file from the file server.
//
// Schemes: https
//
// Security:
// oauth
// Responses:
// 200: fileResponse
r.PathPrefix("/meshclient/files").Handler(http.StripPrefix("/meshclient/files", http.FileServer(http.Dir("./meshclient/files"))))
} }

View File

@@ -19,23 +19,43 @@ import (
) )
func hostHandlers(r *mux.Router) { func hostHandlers(r *mux.Router) {
r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).Methods(http.MethodGet) r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).
r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).Methods(http.MethodPut) Methods(http.MethodGet)
r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).Methods(http.MethodPut) r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).
r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).Methods(http.MethodPost) Methods(http.MethodPut)
r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).Methods(http.MethodPut) r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).
r.HandleFunc("/api/hosts/{hostid}", Authorize(true, false, "all", http.HandlerFunc(deleteHost))).Methods(http.MethodDelete) Methods(http.MethodPut)
r.HandleFunc("/api/hosts/{hostid}/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHost))).Methods(http.MethodPut) r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).
r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).Methods(http.MethodPost) Methods(http.MethodPost)
r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete) r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).
Methods(http.MethodPut)
r.HandleFunc("/api/hosts/{hostid}", Authorize(true, false, "all", http.HandlerFunc(deleteHost))).
Methods(http.MethodDelete)
r.HandleFunc("/api/hosts/{hostid}/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHost))).
Methods(http.MethodPut)
r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).
Methods(http.MethodPost)
r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).
Methods(http.MethodDelete)
r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost) r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost)
r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).Methods(http.MethodGet) r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).
r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).Methods(http.MethodPost) Methods(http.MethodGet)
r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).Methods(http.MethodPut) r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).
r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).Methods(http.MethodDelete) Methods(http.MethodPost)
r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).
Methods(http.MethodPut)
r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).
Methods(http.MethodDelete)
r.HandleFunc("/api/v1/auth-register/host", socketHandler) r.HandleFunc("/api/v1/auth-register/host", socketHandler)
} }
// @Summary Upgrade a host
// @Router /api/hosts/{hostid}/upgrade [put]
// @Tags Hosts
// @Security oauth
// @Param hostid path string true "Host ID"
// @Success 200 {string} string "passed message to upgrade host"
// @Failure 500 {object} models.ErrorResponse
// upgrade host is a handler to send upgrade message to a host // upgrade host is a handler to send upgrade message to a host
func upgradeHost(w http.ResponseWriter, r *http.Request) { func upgradeHost(w http.ResponseWriter, r *http.Request) {
host, err := logic.GetHost(mux.Vars(r)["hostid"]) host, err := logic.GetHost(mux.Vars(r)["hostid"])
@@ -52,17 +72,12 @@ func upgradeHost(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponse(w, r, "passed message to upgrade host") logic.ReturnSuccessResponse(w, r, "passed message to upgrade host")
} }
// swagger:route GET /api/hosts hosts getHosts // @Summary List all hosts
// // @Router /api/hosts [get]
// Lists all hosts. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Success 200 {array} models.ApiHost
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: apiHostSliceResponse
func getHosts(w http.ResponseWriter, r *http.Request) { func getHosts(w http.ResponseWriter, r *http.Request) {
currentHosts, err := logic.GetAllHosts() currentHosts, err := logic.GetAllHosts()
if err != nil { if err != nil {
@@ -77,23 +92,22 @@ func getHosts(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(apiHosts) json.NewEncoder(w).Encode(apiHosts)
} }
// swagger:route GET /api/v1/host hosts pullHost // @Summary Used by clients for "pull" command
// // @Router /api/v1/host [get]
// Used by clients for "pull" command // @Tags Hosts
// // @Security oauth
// Schemes: https // @Success 200 {object} models.HostPull
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: hostPull
func pull(w http.ResponseWriter, r *http.Request) { func pull(w http.ResponseWriter, r *http.Request) {
hostID := r.Header.Get(hostIDHeader) // return JSON/API formatted keys hostID := r.Header.Get(hostIDHeader) // return JSON/API formatted keys
if len(hostID) == 0 { if len(hostID) == 0 {
logger.Log(0, "no host authorized to pull") logger.Log(0, "no host authorized to pull")
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal"),
)
return return
} }
host, err := logic.GetHost(hostID) host, err := logic.GetHost(hostID)
@@ -153,17 +167,14 @@ func pull(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(&response) json.NewEncoder(w).Encode(&response)
} }
// swagger:route PUT /api/hosts/{hostid} hosts updateHost // @Summary Updates a Netclient host on Netmaker server
// // @Router /api/hosts/{hostid} [put]
// Updates a Netclient host on Netmaker server. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Param body body models.ApiHost true "New host data"
// Security: // @Success 200 {object} models.ApiHost
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: apiHostResponse
func updateHost(w http.ResponseWriter, r *http.Request) { func updateHost(w http.ResponseWriter, r *http.Request) {
var newHostData models.ApiHost var newHostData models.ApiHost
err := json.NewDecoder(r.Body).Decode(&newHostData) err := json.NewDecoder(r.Body).Decode(&newHostData)
@@ -194,7 +205,13 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
Action: models.UpdateHost, Action: models.UpdateHost,
Host: *newHost, Host: *newHost,
}); err != nil { }); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to send host update: ", currHost.ID.String(), err.Error()) logger.Log(
0,
r.Header.Get("user"),
"failed to send host update: ",
currHost.ID.String(),
err.Error(),
)
} }
go func() { go func() {
if err := mq.PublishPeerUpdate(false); err != nil { if err := mq.PublishPeerUpdate(false); err != nil {
@@ -213,17 +230,14 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(apiHostData) json.NewEncoder(w).Encode(apiHostData)
} }
// swagger:route PUT /api/v1/fallback/host/{hostid} hosts hostUpdateFallback // @Summary Updates a Netclient host on Netmaker server
// // @Router /api/v1/fallback/host/{hostid} [put]
// Updates a Netclient host on Netmaker server. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Param body body models.HostUpdate true "Host update data"
// Security: // @Success 200 {string} string "updated host data"
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: apiHostResponse
func hostUpdateFallback(w http.ResponseWriter, r *http.Request) { func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
hostid := params["hostid"] hostid := params["hostid"]
@@ -273,17 +287,14 @@ func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponse(w, r, "updated host data") logic.ReturnSuccessResponse(w, r, "updated host data")
} }
// swagger:route DELETE /api/hosts/{hostid} hosts deleteHost // @Summary Deletes a Netclient host from Netmaker server
// // @Router /api/hosts/{hostid} [delete]
// Deletes a Netclient host from Netmaker server. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Param force query bool false "Force delete"
// Security: // @Success 200 {object} models.ApiHost
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: apiHostResponse
func deleteHost(w http.ResponseWriter, r *http.Request) { func deleteHost(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
hostid := params["hostid"] hostid := params["hostid"]
@@ -312,14 +323,26 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
if servercfg.GetBrokerType() == servercfg.EmqxBrokerType { if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
// delete EMQX credentials for host // delete EMQX credentials for host
if err := mq.GetEmqxHandler().DeleteEmqxUser(currHost.ID.String()); err != nil { if err := mq.GetEmqxHandler().DeleteEmqxUser(currHost.ID.String()); err != nil {
slog.Error("failed to remove host credentials from EMQX", "id", currHost.ID, "error", err) slog.Error(
"failed to remove host credentials from EMQX",
"id",
currHost.ID,
"error",
err,
)
} }
} }
if err = mq.HostUpdate(&models.HostUpdate{ if err = mq.HostUpdate(&models.HostUpdate{
Action: models.DeleteHost, Action: models.DeleteHost,
Host: *currHost, Host: *currHost,
}); err != nil { }); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to send delete host update: ", currHost.ID.String(), err.Error()) logger.Log(
0,
r.Header.Get("user"),
"failed to send delete host update: ",
currHost.ID.String(),
err.Error(),
)
} }
if err = logic.RemoveHost(currHost, forceDelete); err != nil { if err = logic.RemoveHost(currHost, forceDelete); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error()) logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
@@ -333,23 +356,25 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(apiHostData) json.NewEncoder(w).Encode(apiHostData)
} }
// swagger:route POST /api/hosts/{hostid}/networks/{network} hosts addHostToNetwork // @Summary To Add Host To Network
// // @Router /api/hosts/{hostid}/networks/{network} [post]
// Given a network, a host is added to the network. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Param network path string true "Network name"
// Security: // @Success 200 {string} string "OK"
// oauth // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: okResponse
func addHostToNetwork(w http.ResponseWriter, r *http.Request) { func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
hostid := params["hostid"] hostid := params["hostid"]
network := params["network"] network := params["network"]
if hostid == "" || network == "" { if hostid == "" || network == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
)
return return
} }
// confirm host exists // confirm host exists
@@ -362,7 +387,14 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
newNode, err := logic.UpdateHostNetwork(currHost, network, true) newNode, err := logic.UpdateHostNetwork(currHost, network, true)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to add host to network:", hostid, network, err.Error()) logger.Log(
0,
r.Header.Get("user"),
"failed to add host to network:",
hostid,
network,
err.Error(),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -384,21 +416,23 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
logic.SetDNS() logic.SetDNS()
} }
}() }()
logger.Log(2, r.Header.Get("user"), fmt.Sprintf("added host %s to network %s", currHost.Name, network)) logger.Log(
2,
r.Header.Get("user"),
fmt.Sprintf("added host %s to network %s", currHost.Name, network),
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route DELETE /api/hosts/{hostid}/networks/{network} hosts deleteHostFromNetwork // @Summary To Remove Host from Network
// // @Router /api/hosts/{hostid}/networks/{network} [delete]
// Given a network, a host is removed from the network. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Param network path string true "Network name"
// Security: // @Param force query bool false "Force delete"
// oauth // @Success 200 {string} string "OK"
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: okResponse
func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) { func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -406,7 +440,11 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
network := params["network"] network := params["network"]
forceDelete := r.URL.Query().Get("force") == "true" forceDelete := r.URL.Query().Get("force") == "true"
if hostid == "" || network == "" { if hostid == "" || network == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
)
return return
} }
// confirm host exists // confirm host exists
@@ -416,14 +454,29 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
// check if there is any daemon nodes that needs to be deleted // check if there is any daemon nodes that needs to be deleted
node, err := logic.GetNodeByHostRef(hostid, network) node, err := logic.GetNodeByHostRef(hostid, network)
if err != nil { if err != nil {
slog.Error("couldn't get node for host", "hostid", hostid, "network", network, "error", err) slog.Error(
"couldn't get node for host",
"hostid",
hostid,
"network",
network,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
if err = logic.DeleteNodeByID(&node); err != nil { if err = logic.DeleteNodeByID(&node); err != nil {
slog.Error("failed to force delete daemon node", slog.Error("failed to force delete daemon node",
"nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err) "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to force delete daemon node: "+err.Error()), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to force delete daemon node: "+err.Error()),
"internal",
),
)
return return
} }
logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully") logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
@@ -441,20 +494,42 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
// force cleanup the node // force cleanup the node
node, err := logic.GetNodeByHostRef(hostid, network) node, err := logic.GetNodeByHostRef(hostid, network)
if err != nil { if err != nil {
slog.Error("couldn't get node for host", "hostid", hostid, "network", network, "error", err) slog.Error(
"couldn't get node for host",
"hostid",
hostid,
"network",
network,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
if err = logic.DeleteNodeByID(&node); err != nil { if err = logic.DeleteNodeByID(&node); err != nil {
slog.Error("failed to force delete daemon node", slog.Error("failed to force delete daemon node",
"nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err) "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to force delete daemon node: "+err.Error()), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to force delete daemon node: "+err.Error()),
"internal",
),
)
return return
} }
logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully") logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
return return
} }
logger.Log(0, r.Header.Get("user"), "failed to remove host from network:", hostid, network, err.Error()) logger.Log(
0,
r.Header.Get("user"),
"failed to remove host from network:",
hostid,
network,
err.Error(),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -464,7 +539,11 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
} }
logger.Log(1, "deleting node", node.ID.String(), "from host", currHost.Name) logger.Log(1, "deleting node", node.ID.String(), "from host", currHost.Name)
if err := logic.DeleteNode(node, forceDelete); err != nil { if err := logic.DeleteNode(node, forceDelete); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("failed to delete node"), "internal"),
)
return return
} }
go func() { go func() {
@@ -473,21 +552,23 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
logic.SetDNS() logic.SetDNS()
} }
}() }()
logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network)) logger.Log(
2,
r.Header.Get("user"),
fmt.Sprintf("removed host %s from network %s", currHost.Name, network),
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route POST /api/hosts/adm/authenticate authenticate authenticateHost // @Summary To Fetch Auth Token for a Host
// // @Router /api/hosts/adm/authenticate [post]
// Host based authentication for making further API calls. // @Tags Auth
// // @Accept json
// Schemes: https // @Param body body models.AuthParams true "Authentication parameters"
// // @Success 200 {object} models.SuccessResponse
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 401 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: successResponse
func authenticateHost(response http.ResponseWriter, request *http.Request) { func authenticateHost(response http.ResponseWriter, request *http.Request) {
var authRequest models.AuthParams var authRequest models.AuthParams
var errorResponse = models.ErrorResponse{ var errorResponse = models.ErrorResponse{
@@ -579,17 +660,14 @@ func authenticateHost(response http.ResponseWriter, request *http.Request) {
response.Write(successJSONResponse) response.Write(successJSONResponse)
} }
// swagger:route POST /api/hosts/{hostid}/signalpeer hosts signalPeer // @Summary Send signal to peer
// // @Router /api/v1/host/{hostid}/signalpeer [post]
// send signal to peer. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Param body body models.Signal true "Signal data"
// Security: // @Success 200 {object} models.Signal
// oauth // @Failure 400 {object} models.ErrorResponse
//
// Responses:
// 200: signal
func signalPeer(w http.ResponseWriter, r *http.Request) { func signalPeer(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
hostid := params["hostid"] hostid := params["hostid"]
@@ -617,7 +695,11 @@ func signalPeer(w http.ResponseWriter, r *http.Request) {
signal.IsPro = servercfg.IsPro signal.IsPro = servercfg.IsPro
peerHost, err := logic.GetHost(signal.ToHostID) peerHost, err := logic.GetHost(signal.ToHostID)
if err != nil { if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"),
)
return return
} }
err = mq.HostUpdate(&models.HostUpdate{ err = mq.HostUpdate(&models.HostUpdate{
@@ -626,7 +708,14 @@ func signalPeer(w http.ResponseWriter, r *http.Request) {
Signal: signal, Signal: signal,
}) })
if err != nil { if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to publish signal to peer: "+err.Error()), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("failed to publish signal to peer: "+err.Error()),
"badrequest",
),
)
return return
} }
@@ -634,17 +723,12 @@ func signalPeer(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(signal) json.NewEncoder(w).Encode(signal)
} }
// swagger:route POST /api/hosts/keys hosts updateAllKeys // @Summary Update keys for all hosts
// // @Router /api/hosts/keys [put]
// Update keys for a network. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Success 200 {string} string "OK"
// // @Failure 400 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: networkBodyResponse
func updateAllKeys(w http.ResponseWriter, r *http.Request) { func updateAllKeys(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{} var errorResponse = models.ErrorResponse{}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -664,7 +748,12 @@ func updateAllKeys(w http.ResponseWriter, r *http.Request) {
hostUpdate.Host = host hostUpdate.Host = host
logger.Log(2, "updating host", host.ID.String(), " for a key update") logger.Log(2, "updating host", host.ID.String(), " for a key update")
if err = mq.HostUpdate(&hostUpdate); err != nil { if err = mq.HostUpdate(&hostUpdate); err != nil {
logger.Log(0, "failed to send update to node during a network wide key update", host.ID.String(), err.Error()) logger.Log(
0,
"failed to send update to node during a network wide key update",
host.ID.String(),
err.Error(),
)
} }
} }
}() }()
@@ -672,17 +761,13 @@ func updateAllKeys(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route POST /api/hosts/{hostid}keys hosts updateKeys // @Summary Update keys for a host
// // @Router /api/hosts/{hostid}/keys [put]
// Update keys for a network. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Success 200 {string} string "OK"
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: networkBodyResponse
func updateKeys(w http.ResponseWriter, r *http.Request) { func updateKeys(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{} var errorResponse = models.ErrorResponse{}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -711,17 +796,13 @@ func updateKeys(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route POST /api/hosts/{hostid}/sync hosts synchost // @Summary Requests a host to pull
// // @Router /api/hosts/{hostid}/sync [post]
// Requests a host to pull. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Param hostid path string true "Host ID"
// // @Success 200 {string} string "OK"
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: networkBodyResponse
func syncHost(w http.ResponseWriter, r *http.Request) { func syncHost(w http.ResponseWriter, r *http.Request) {
hostId := mux.Vars(r)["hostid"] hostId := mux.Vars(r)["hostid"]
@@ -751,17 +832,12 @@ func syncHost(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route DELETE /api/emqx/hosts hosts delEmqxHosts // @Summary Deletes all EMQX hosts
// // @Router /api/emqx/hosts [delete]
// Lists all hosts. // @Tags Hosts
// // @Security oauth
// Schemes: https // @Success 200 {string} string "deleted hosts data on emqx"
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: apiHostResponse
func delEmqxHosts(w http.ResponseWriter, r *http.Request) { func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
currentHosts, err := logic.GetAllHosts() currentHosts, err := logic.GetAllHosts()
if err != nil { if err != nil {
@@ -777,7 +853,13 @@ func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
} }
err = mq.GetEmqxHandler().DeleteEmqxUser(servercfg.GetMqUserName()) err = mq.GetEmqxHandler().DeleteEmqxUser(servercfg.GetMqUserName())
if err != nil { if err != nil {
slog.Error("failed to remove server credentials from EMQX", "user", servercfg.GetMqUserName(), "error", err) slog.Error(
"failed to remove server credentials from EMQX",
"user",
servercfg.GetMqUserName(),
"error",
err,
)
} }
logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx") logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx")
} }

View File

@@ -15,17 +15,12 @@ func ipHandlers(r *mux.Router) {
r.HandleFunc("/api/getip", http.HandlerFunc(getPublicIP)).Methods(http.MethodGet) r.HandleFunc("/api/getip", http.HandlerFunc(getPublicIP)).Methods(http.MethodGet)
} }
// swagger:route GET /api/getip ipservice getPublicIP // @Summary Get the current public IP address.
// // @Router /api/getip [get]
// Get the current public IP address. // @Tags IP Service
// // @Security oauth2
// Schemes: https // @Success 200 {string} string "The public IP address."
// // @Failure 400 {string} string "Invalid IP address or no IP found."
// Security:
// oauth
//
// Responses:
// 200: byteArrayResponse
func getPublicIP(w http.ResponseWriter, r *http.Request) { func getPublicIP(w http.ResponseWriter, r *http.Request) {
r.Header.Set("Connection", "close") r.Header.Set("Connection", "close")
ip, err := parseIP(r) ip, err := parseIP(r)

View File

@@ -9,20 +9,16 @@ import (
) )
func legacyHandlers(r *mux.Router) { func legacyHandlers(r *mux.Router) {
r.HandleFunc("/api/v1/legacy/nodes", logic.SecurityCheck(true, http.HandlerFunc(wipeLegacyNodes))).Methods(http.MethodDelete) r.HandleFunc("/api/v1/legacy/nodes", logic.SecurityCheck(true, http.HandlerFunc(wipeLegacyNodes))).
Methods(http.MethodDelete)
} }
// swagger:route DELETE /api/v1/legacy/nodes nodes wipeLegacyNodes // @Summary Delete all legacy nodes from DB.
// // @Router /api/v1/legacy/nodes [delete]
// Delete all legacy nodes from DB. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {string} string "Wiped all legacy nodes."
// // @Failure 400 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: successResponse
func wipeLegacyNodes(w http.ResponseWriter, r *http.Request) { func wipeLegacyNodes(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@@ -22,28 +22,32 @@ import (
) )
func networkHandlers(r *mux.Router) { func networkHandlers(r *mux.Router) {
r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))).Methods(http.MethodGet) r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))).
r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, http.HandlerFunc(createNetwork)))).Methods(http.MethodPost) Methods(http.MethodGet)
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(getNetwork))).Methods(http.MethodGet) r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, http.HandlerFunc(createNetwork)))).
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).Methods(http.MethodDelete) Methods(http.MethodPost)
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).Methods(http.MethodPut) r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(getNetwork))).
Methods(http.MethodGet)
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).
Methods(http.MethodDelete)
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).
Methods(http.MethodPut)
// ACLs // ACLs
r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACL))).Methods(http.MethodPut) r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACL))).
r.HandleFunc("/api/networks/{networkname}/acls/v2", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACLv2))).Methods(http.MethodPut) Methods(http.MethodPut)
r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(getNetworkACL))).Methods(http.MethodGet) r.HandleFunc("/api/networks/{networkname}/acls/v2", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACLv2))).
Methods(http.MethodPut)
r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(getNetworkACL))).
Methods(http.MethodGet)
} }
// swagger:route GET /api/networks networks getNetworks // @Summary Lists all networks
// // @Router /api/networks [get]
// Lists all networks. // @Tags Networks
// // @Security oauth
// Schemes: https // @Produce json
// // @Success 200 {object} models.Network
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: getNetworksSliceResponse
func getNetworks(w http.ResponseWriter, r *http.Request) { func getNetworks(w http.ResponseWriter, r *http.Request) {
var err error var err error
@@ -61,17 +65,14 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(allnetworks) json.NewEncoder(w).Encode(allnetworks)
} }
// swagger:route GET /api/networks/{networkname} networks getNetwork // @Summary Get a network
// // @Router /api/networks/{networkname} [get]
// Get a network. // @Tags Networks
// // @Security oauth
// Schemes: https // @Param networkname path string true "Network name"
// // @Produce json
// Security: // @Success 200 {object} models.Network
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: networkBodyResponse
func getNetwork(w http.ResponseWriter, r *http.Request) { func getNetwork(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -90,17 +91,16 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(network) json.NewEncoder(w).Encode(network)
} }
// swagger:route PUT /api/networks/{networkname}/acls networks updateNetworkACL // @Summary Update a network ACL (Access Control List)
// // @Router /api/networks/{networkname}/acls [put]
// Update a network ACL (Access Control List). // @Tags Networks
// // @Security oauth
// Schemes: https // @Param networkname path string true "Network name"
// // @Param body body acls.ACLContainer true "ACL container"
// Security: // @Produce json
// oauth // @Success 200 {object} acls.ACLContainer
// // @Failure 400 {object} models.ErrorResponse
// Responses: // @Failure 500 {object} models.ErrorResponse
// 200: aclContainerResponse
func updateNetworkACL(w http.ResponseWriter, r *http.Request) { func updateNetworkACL(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -140,17 +140,16 @@ func updateNetworkACL(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(newNetACL) json.NewEncoder(w).Encode(newNetACL)
} }
// swagger:route PUT /api/networks/{networkname}/acls/v2 networks updateNetworkACL // @Summary Update a network ACL (Access Control List)
// // @Router /api/networks/{networkname}/acls/v2 [put]
// Update a network ACL (Access Control List). // @Tags Networks
// // @Security oauth
// Schemes: https // @Param networkname path string true "Network name"
// // @Param body body acls.ACLContainer true "ACL container"
// Security: // @Produce json
// oauth // @Success 200 {object} acls.ACLContainer
// // @Failure 400 {object} models.ErrorResponse
// Responses: // @Failure 500 {object} models.ErrorResponse
// 200: aclContainerResponse
func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) { func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -279,13 +278,25 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
client := client client := client
err := logic.DeleteExtClient(client.Network, client.ClientID) err := logic.DeleteExtClient(client.Network, client.ClientID)
if err != nil { if err != nil {
slog.Error("failed to delete client during update", "client", client.ClientID, "error", err.Error()) slog.Error(
"failed to delete client during update",
"client",
client.ClientID,
"error",
err.Error(),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
err = logic.SaveExtClient(&client) err = logic.SaveExtClient(&client)
if err != nil { if err != nil {
slog.Error("failed to save client during update", "client", client.ClientID, "error", err.Error()) slog.Error(
"failed to save client during update",
"client",
client.ClientID,
"error",
err.Error(),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -310,7 +321,11 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
// update ingress gateways of associated clients // update ingress gateways of associated clients
hosts, err := logic.GetAllHosts() hosts, err := logic.GetAllHosts()
if err != nil { if err != nil {
slog.Error("failed to fetch hosts after network ACL update. skipping publish extclients ACL", "network", netname) slog.Error(
"failed to fetch hosts after network ACL update. skipping publish extclients ACL",
"network",
netname,
)
return return
} }
hostsMap := make(map[uuid.UUID]models.Host) hostsMap := make(map[uuid.UUID]models.Host)
@@ -320,7 +335,13 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
for hostId, clients := range assocClientsToDisconnectPerHost { for hostId, clients := range assocClientsToDisconnectPerHost {
if host, ok := hostsMap[hostId]; ok { if host, ok := hostsMap[hostId]; ok {
if err = mq.PublishSingleHostPeerUpdate(&host, allNodes, nil, clients, false); err != nil { if err = mq.PublishSingleHostPeerUpdate(&host, allNodes, nil, clients, false); err != nil {
slog.Error("failed to publish peer update to ingress after ACL update on network", "network", netname, "host", hostId) slog.Error(
"failed to publish peer update to ingress after ACL update on network",
"network",
netname,
"host",
hostId,
)
} }
} }
} }
@@ -330,17 +351,14 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(networkACLChange) json.NewEncoder(w).Encode(networkACLChange)
} }
// swagger:route GET /api/networks/{networkname}/acls networks getNetworkACL // @Summary Get a network ACL (Access Control List)
// // @Router /api/networks/{networkname}/acls [get]
// Get a network ACL (Access Control List). // @Tags Networks
// // @Security oauth
// Schemes: https // @Param networkname path string true "Network name"
// // @Produce json
// Security: // @Success 200 {object} acls.ACLContainer
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: aclContainerResponse
func getNetworkACL(w http.ResponseWriter, r *http.Request) { func getNetworkACL(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -364,17 +382,15 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(networkACL) json.NewEncoder(w).Encode(networkACL)
} }
// swagger:route DELETE /api/networks/{networkname} networks deleteNetwork // @Summary Delete a network
// // @Router /api/networks/{networkname} [delete]
// Delete a network. Will not delete if there are any nodes that belong to the network. // @Tags Networks
// // @Security oauth
// Schemes: https // @Param networkname path string true "Network name"
// // @Produce json
// Security: // @Success 200 {object} models.SuccessResponse
// oauth // @Failure 400 {object} models.ErrorResponse
// // @Failure 403 {object} models.ErrorResponse
// Responses:
// 200: successResponse
func deleteNetwork(w http.ResponseWriter, r *http.Request) { func deleteNetwork(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -398,17 +414,14 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode("success") json.NewEncoder(w).Encode("success")
} }
// swagger:route POST /api/networks networks createNetwork // @Summary Create a network
// // @Router /api/networks [post]
// Create a network. // @Tags Networks
// // @Security oauth
// Schemes: https // @Param body body models.Network true "Network details"
// // @Produce json
// Security: // @Success 200 {object} models.Network
// oauth // @Failure 400 {object} models.ErrorResponse
//
// Responses:
// 200: networkBodyResponse
func createNetwork(w http.ResponseWriter, r *http.Request) { func createNetwork(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -473,7 +486,14 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
currHost := &defaultHosts[i] currHost := &defaultHosts[i]
newNode, err := logic.UpdateHostNetwork(currHost, network.NetID, true) newNode, err := logic.UpdateHostNetwork(currHost, network.NetID, true)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to add host to network:", currHost.ID.String(), network.NetID, err.Error()) logger.Log(
0,
r.Header.Get("user"),
"failed to add host to network:",
currHost.ID.String(),
network.NetID,
err.Error(),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -483,7 +503,14 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
Host: *currHost, Host: *currHost,
Node: *newNode, Node: *newNode,
}); err != nil { }); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to add host to network:", currHost.ID.String(), network.NetID, err.Error()) logger.Log(
0,
r.Header.Get("user"),
"failed to add host to network:",
currHost.ID.String(),
network.NetID,
err.Error(),
)
} }
// make host failover // make host failover
logic.CreateFailOver(*newNode) logic.CreateFailOver(*newNode)
@@ -501,17 +528,15 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(network) json.NewEncoder(w).Encode(network)
} }
// swagger:route PUT /api/networks/{networkname} networks updateNetwork // @Summary Update network settings
// // @Router /api/networks/{networkname} [put]
// Update pro settings for a network. // @Tags Networks
// // @Security oauth
// Schemes: https // @Param networkname path string true "Network name"
// // @Param body body models.Network true "Network details"
// Security: // @Produce json
// oauth // @Success 200 {object} models.Network
// // @Failure 400 {object} models.ErrorResponse
// Responses:
// 200: networkBodyResponse
func updateNetwork(w http.ResponseWriter, r *http.Request) { func updateNetwork(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@@ -21,30 +21,28 @@ var hostIDHeader = "host-id"
func nodeHandlers(r *mux.Router) { func nodeHandlers(r *mux.Router) {
r.HandleFunc("/api/nodes", Authorize(false, false, "user", http.HandlerFunc(getAllNodes))).Methods(http.MethodGet) r.HandleFunc("/api/nodes", Authorize(false, false, "user", http.HandlerFunc(getAllNodes))).
r.HandleFunc("/api/nodes/{network}", Authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods(http.MethodGet) Methods(http.MethodGet)
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet) r.HandleFunc("/api/nodes/{network}", Authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).
r.HandleFunc("/api/nodes/{network}/{nodeid}", logic.SecurityCheck(true, http.HandlerFunc(updateNode))).Methods(http.MethodPut) Methods(http.MethodGet)
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).
r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost) Methods(http.MethodGet)
r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", logic.SecurityCheck(true, http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}", logic.SecurityCheck(true, http.HandlerFunc(updateNode))).
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost) Methods(http.MethodPut)
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).
Methods(http.MethodDelete)
r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).
Methods(http.MethodPost)
r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", logic.SecurityCheck(true, http.HandlerFunc(deleteEgressGateway))).
Methods(http.MethodDelete)
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).
Methods(http.MethodPost)
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteIngressGateway))).
Methods(http.MethodDelete)
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost) r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost) r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
} }
// swagger:route POST /api/nodes/adm/{network}/authenticate authenticate authenticate
//
// Authenticate to make further API calls related to a network.
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: successResponse
func authenticate(response http.ResponseWriter, request *http.Request) { func authenticate(response http.ResponseWriter, request *http.Request) {
var authRequest models.AuthParams var authRequest models.AuthParams
@@ -149,7 +147,11 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
// even if it's technically ok // even if it's technically ok
// This is kind of a poor man's RBAC. There's probably a better/smarter way. // This is kind of a poor man's RBAC. There's probably a better/smarter way.
// TODO: Consider better RBAC implementations // TODO: Consider better RBAC implementations
func Authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc { func Authorize(
hostAllowed, networkCheck bool,
authNetwork string,
next http.Handler,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{ var errorResponse = models.ErrorResponse{
Code: http.StatusForbidden, Message: logic.Forbidden_Msg, Code: http.StatusForbidden, Message: logic.Forbidden_Msg,
@@ -258,17 +260,12 @@ func Authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Han
} }
} }
// swagger:route GET /api/nodes/{network} nodes getNetworkNodes // @Summary Gets all nodes associated with network including pending nodes
// // @Router /api/nodes/adm/{network} [get]
// Gets all nodes associated with network including pending nodes. // @Securitydefinitions.oauth2.application OAuth2Application
// // @Tags Nodes
// Schemes: https // @Success 200 {array} models.Node
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeSliceResponse
func getNetworkNodes(w http.ResponseWriter, r *http.Request) { func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -288,18 +285,12 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(apiNodes) json.NewEncoder(w).Encode(apiNodes)
} }
// swagger:route GET /api/nodes nodes getAllNodes // @Summary Get all nodes across all networks
// // @Router /api/nodes [get]
// Get all nodes across all networks. // @Tags Nodes
// // @Securitydefinitions.oauth2.application OAuth2Application
// Schemes: https // @Success 200 {array} models.ApiNode
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeSliceResponse
//
// Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not // Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
func getAllNodes(w http.ResponseWriter, r *http.Request) { func getAllNodes(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -327,17 +318,12 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(apiNodes) json.NewEncoder(w).Encode(apiNodes)
} }
// swagger:route GET /api/nodes/{network}/{nodeid} nodes getNode // @Summary Get an individual node
// // @Router /api/nodes/{network}/{nodeid} [get]
// Get an individual node. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.NodeGet
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
func getNode(w http.ResponseWriter, r *http.Request) { func getNode(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -359,15 +345,29 @@ func getNode(w http.ResponseWriter, r *http.Request) {
} }
allNodes, err := logic.GetAllNodes() allNodes, err := logic.GetAllNodes()
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(
fmt.Sprintf("error fetching wg peers config for host [ %s ]: %v", host.ID.String(), err)) 0,
r.Header.Get("user"),
fmt.Sprintf(
"error fetching wg peers config for host [ %s ]: %v",
host.ID.String(),
err,
),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
hostPeerUpdate, err := logic.GetPeerUpdateForHost(node.Network, host, allNodes, nil, nil) hostPeerUpdate, err := logic.GetPeerUpdateForHost(node.Network, host, allNodes, nil, nil)
if err != nil && !database.IsEmptyRecord(err) { if err != nil && !database.IsEmptyRecord(err) {
logger.Log(0, r.Header.Get("user"), logger.Log(
fmt.Sprintf("error fetching wg peers config for host [ %s ]: %v", host.ID.String(), err)) 0,
r.Header.Get("user"),
fmt.Sprintf(
"error fetching wg peers config for host [ %s ]: %v",
host.ID.String(),
err,
),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -388,17 +388,12 @@ func getNode(w http.ResponseWriter, r *http.Request) {
// == EGRESS == // == EGRESS ==
// swagger:route POST /api/nodes/{network}/{nodeid}/creategateway nodes createEgressGateway // @Summary Create an egress gateway
// // @Router /api/nodes/{network}/{nodeid}/creategateway [post]
// Create an egress gateway. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ApiNode
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
func createEgressGateway(w http.ResponseWriter, r *http.Request) { func createEgressGateway(w http.ResponseWriter, r *http.Request) {
var gateway models.EgressGatewayRequest var gateway models.EgressGatewayRequest
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -431,7 +426,14 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
} }
apiNode := node.ConvertToAPINode() apiNode := node.ConvertToAPINode()
logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID) logger.Log(
1,
r.Header.Get("user"),
"created egress gateway on node",
gateway.NodeID,
"on network",
gateway.NetID,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
go func() { go func() {
@@ -442,17 +444,12 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
}() }()
} }
// swagger:route DELETE /api/nodes/{network}/{nodeid}/deletegateway nodes deleteEgressGateway // @Summary Delete an egress gateway
// // @Router /api/nodes/{network}/{nodeid}/deletegateway [delete]
// Delete an egress gateway. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ApiNode
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
func deleteEgressGateway(w http.ResponseWriter, r *http.Request) { func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -474,7 +471,14 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
} }
apiNode := node.ConvertToAPINode() apiNode := node.ConvertToAPINode()
logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid) logger.Log(
1,
r.Header.Get("user"),
"deleted egress gateway on node",
nodeid,
"on network",
netid,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
go func() { go func() {
@@ -487,17 +491,12 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
// == INGRESS == // == INGRESS ==
// swagger:route POST /api/nodes/{network}/{nodeid}/createingress nodes createIngressGateway // @Summary Create an remote access gateway
// // @Router /api/nodes/{network}/{nodeid}/createingress [post]
// Create an ingress gateway. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ApiNode
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
func createIngressGateway(w http.ResponseWriter, r *http.Request) { func createIngressGateway(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -520,7 +519,14 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
} }
apiNode := node.ConvertToAPINode() apiNode := node.ConvertToAPINode()
logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid) logger.Log(
1,
r.Header.Get("user"),
"created ingress gateway on node",
nodeid,
"on network",
netid,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
go func() { go func() {
@@ -530,17 +536,12 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
}() }()
} }
// swagger:route DELETE /api/nodes/{network}/{nodeid}/deleteingress nodes deleteIngressGateway // @Summary Delete an remote access gateway
// // @Router /api/nodes/{network}/{nodeid}/deleteingress [delete]
// Delete an ingress gateway. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ApiNode
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
func deleteIngressGateway(w http.ResponseWriter, r *http.Request) { func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -596,7 +597,13 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
slog.Error("publishSingleHostUpdate", "host", host.Name, "error", err) slog.Error("publishSingleHostUpdate", "host", host.Name, "error", err)
} }
if err := mq.NodeUpdate(&node); err != nil { if err := mq.NodeUpdate(&node); err != nil {
slog.Error("error publishing node update to node", "node", node.ID, "error", err) slog.Error(
"error publishing node update to node",
"node",
node.ID,
"error",
err,
)
} }
if servercfg.IsDNSMode() { if servercfg.IsDNSMode() {
logic.SetDNS() logic.SetDNS()
@@ -606,17 +613,12 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
} }
} }
// swagger:route PUT /api/nodes/{network}/{nodeid} nodes updateNode // @Summary Update an individual node
// // @Router /api/nodes/{network}/{nodeid} [put]
// Update an individual node. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ApiNode
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
func updateNode(w http.ResponseWriter, r *http.Request) { func updateNode(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -642,7 +644,11 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
} }
newNode := newData.ConvertToServerNode(&currentNode) newNode := newData.ConvertToServerNode(&currentNode)
if newNode == nil { if newNode == nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("error converting node"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("error converting node"), "badrequest"),
)
return return
} }
if newNode.IsInternetGateway != currentNode.IsInternetGateway { if newNode.IsInternetGateway != currentNode.IsInternetGateway {
@@ -686,7 +692,14 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
} }
apiNode := newNode.ConvertToAPINode() apiNode := newNode.ConvertToAPINode()
logger.Log(1, r.Header.Get("user"), "updated node", currentNode.ID.String(), "on network", currentNode.Network) logger.Log(
1,
r.Header.Get("user"),
"updated node",
currentNode.ID.String(),
"on network",
currentNode.Network,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
go func(aclUpdate, relayupdate bool, newNode *models.Node) { go func(aclUpdate, relayupdate bool, newNode *models.Node) {
@@ -704,17 +717,12 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
}(aclUpdate, relayUpdate, newNode) }(aclUpdate, relayUpdate, newNode)
} }
// swagger:route DELETE /api/nodes/{network}/{nodeid} nodes deleteNode // @Summary Delete an individual node
// // @Router /api/nodes/{network}/{nodeid} [delete]
// Delete an individual node. // @Tags Nodes
// // @Security oauth2
// Schemes: https // @Success 200 {string} string "Node deleted."
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
func deleteNode(w http.ResponseWriter, r *http.Request) { func deleteNode(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -735,7 +743,11 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
} }
purge := forceDelete || fromNode purge := forceDelete || fromNode
if err := logic.DeleteNode(&node, purge); err != nil { if err := logic.DeleteNode(&node, purge); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("failed to delete node"), "internal"),
)
return return
} }

View File

@@ -102,18 +102,12 @@ func getUsage(w http.ResponseWriter, _ *http.Request) {
}) })
} }
// swagger:route GET /api/server/status server getStatus // @Summary Get the server status
// // @Router /api/server/status [get]
// Get the server configuration. // @Tags Server
// // @Security oauth2
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: serverConfigResponse
func getStatus(w http.ResponseWriter, r *http.Request) { func getStatus(w http.ResponseWriter, r *http.Request) {
// @Success 200 {object} status
type status struct { type status struct {
DB bool `json:"db_connected"` DB bool `json:"db_connected"`
Broker bool `json:"broker_connected"` Broker bool `json:"broker_connected"`
@@ -131,7 +125,8 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
var trialEndDate time.Time var trialEndDate time.Time
var err error var err error
isOnTrial := false isOnTrial := false
if servercfg.IsPro && (servercfg.GetLicenseKey() == "" || servercfg.GetNetmakerTenantID() == "") { if servercfg.IsPro &&
(servercfg.GetLicenseKey() == "" || servercfg.GetNetmakerTenantID() == "") {
trialEndDate, err = logic.GetTrialEndDate() trialEndDate, err = logic.GetTrialEndDate()
if err != nil { if err != nil {
slog.Error("failed to get trial end date", "error", err) slog.Error("failed to get trial end date", "error", err)
@@ -177,17 +172,11 @@ func allowUsers(next http.Handler) http.HandlerFunc {
} }
} }
// swagger:route GET /api/server/getserverinfo server getServerInfo // @Summary Get the server information
// // @Router /api/server/getserverinfo [get]
// Get the server configuration. // @Tags Server
// // @Security oauth2
// Schemes: https // @Success 200 {object} models.ServerConfig
//
// Security:
// oauth
//
// Responses:
// 200: serverConfigResponse
func getServerInfo(w http.ResponseWriter, r *http.Request) { func getServerInfo(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -198,17 +187,11 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) {
// w.WriteHeader(http.StatusOK) // w.WriteHeader(http.StatusOK)
} }
// swagger:route GET /api/server/getconfig server getConfig // @Summary Get the server configuration
// // @Router /api/server/getconfig [get]
// Get the server configuration. // @Tags Server
// // @Security oauth2
// Schemes: https // @Success 200 {object} config.ServerConfig
//
// Security:
// oauth
//
// Responses:
// 200: serverConfigResponse
func getConfig(w http.ResponseWriter, r *http.Request) { func getConfig(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@@ -25,31 +25,39 @@ var (
func userHandlers(r *mux.Router) { func userHandlers(r *mux.Router) {
r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet) r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)
r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost) r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)
r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).Methods(http.MethodPost) r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).
Methods(http.MethodPost)
r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost) r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).Methods(http.MethodPut) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost) Methods(http.MethodPut)
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet) Methods(http.MethodPost)
r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(getPendingUsers))).Methods(http.MethodGet) Methods(http.MethodDelete)
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(deleteAllPendingUsers))).Methods(http.MethodDelete) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(deletePendingUser))).Methods(http.MethodDelete) Methods(http.MethodGet)
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingUser))).Methods(http.MethodPost) r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).
Methods(http.MethodGet)
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(getPendingUsers))).
Methods(http.MethodGet)
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(deleteAllPendingUsers))).
Methods(http.MethodDelete)
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(deletePendingUser))).
Methods(http.MethodDelete)
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingUser))).
Methods(http.MethodPost)
} }
// swagger:route POST /api/users/adm/authenticate authenticate authenticateUser // @Summary Authenticate a user to retrieve an authorization token
// // @Router /api/users/adm/authenticate [post]
// User authenticates using its password and retrieves a JWT for authorization. // @Tags Auth
// // @Accept json
// Schemes: https // @Param body body models.UserAuthParams true "Authentication parameters"
// // @Success 200 {object} models.SuccessResponse
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 401 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: successResponse
func authenticateUser(response http.ResponseWriter, request *http.Request) { func authenticateUser(response http.ResponseWriter, request *http.Request) {
// Auth request consists of Mac Address and Password (from node that is authorizing // Auth request consists of Mac Address and Password (from node that is authorizing
@@ -60,7 +68,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
} }
if !servercfg.IsBasicAuthEnabled() { if !servercfg.IsBasicAuthEnabled() {
logic.ReturnErrorResponse(response, request, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest")) logic.ReturnErrorResponse(
response,
request,
logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
)
return return
} }
@@ -83,7 +95,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
return return
} }
if !(user.IsAdmin || user.IsSuperAdmin) { if !(user.IsAdmin || user.IsSuperAdmin) {
logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("only admins can access dashboard"), "unauthorized")) logic.ReturnErrorResponse(
response,
request,
logic.FormatError(errors.New("only admins can access dashboard"), "unauthorized"),
)
return return
} }
} }
@@ -99,7 +115,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
if jwt == "" { if jwt == "" {
// very unlikely that err is !nil and no jwt returned, but handle it anyways. // very unlikely that err is !nil and no jwt returned, but handle it anyways.
logger.Log(0, username, "jwt token is empty") logger.Log(0, username, "jwt token is empty")
logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("no token returned"), "internal")) logic.ReturnErrorResponse(
response,
request,
logic.FormatError(errors.New("no token returned"), "internal"),
)
return return
} }
@@ -133,9 +153,19 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
} }
for _, client := range clients { for _, client := range clients {
if client.OwnerID == username && !client.Enabled { if client.OwnerID == username && !client.Enabled {
slog.Info(fmt.Sprintf("enabling ext client %s for user %s due to RAC autodisabling feature", client.ClientID, client.OwnerID)) slog.Info(
fmt.Sprintf(
"enabling ext client %s for user %s due to RAC autodisabling feature",
client.ClientID,
client.OwnerID,
),
)
if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil { if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil {
slog.Error("error enabling ext client in RAC autodisable hook", "error", err) slog.Error(
"error enabling ext client in RAC autodisable hook",
"error",
err,
)
continue // dont return but try for other clients continue // dont return but try for other clients
} else { } else {
// publish peer update to ingress gateway // publish peer update to ingress gateway
@@ -151,17 +181,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
}() }()
} }
// swagger:route GET /api/users/adm/hassuperadmin user hasSuperAdmin // @Summary Check if the server has a super admin
// // @Router /api/users/adm/hassuperadmin [get]
// Checks whether the server has an admin. // @Tags Users
// // @Success 200 {object} bool
// Schemes: https // @Failure 500 {object} models.ErrorResponse
//
// Security:
// oauth
//
// Responses:
// 200: hasAdmin
func hasSuperAdmin(w http.ResponseWriter, r *http.Request) { func hasSuperAdmin(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -177,17 +201,12 @@ func hasSuperAdmin(w http.ResponseWriter, r *http.Request) {
} }
// swagger:route GET /api/users/{username} user getUser // @Summary Get an individual user
// // @Router /api/users/{username} [get]
// Get an individual user. // @Tags Users
// // @Param username path string true "Username of the user to fetch"
// Schemes: https // @Success 200 {object} models.User
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func getUser(w http.ResponseWriter, r *http.Request) { func getUser(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -205,17 +224,11 @@ func getUser(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(user) json.NewEncoder(w).Encode(user)
} }
// swagger:route GET /api/users user getUsers // @Summary Get all users
// // @Router /api/users [get]
// Get all users. // @Tags Users
// // @Success 200 {array} models.User
// Schemes: https // @Failure 500 {object} models.ErrorResponse
//
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func getUsers(w http.ResponseWriter, r *http.Request) { func getUsers(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -233,17 +246,13 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(users) json.NewEncoder(w).Encode(users)
} }
// swagger:route POST /api/users/adm/createsuperadmin user createAdmin // @Summary Create a super admin
// // @Router /api/users/adm/createsuperadmin [post]
// Make a user an admin. // @Tags Users
// // @Param body body models.User true "User details"
// Schemes: https // @Success 200 {object} models.User
// // @Failure 400 {object} models.ErrorResponse
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: userBodyResponse
func createSuperAdmin(w http.ResponseWriter, r *http.Request) { func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -257,7 +266,11 @@ func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
} }
if !servercfg.IsBasicAuthEnabled() { if !servercfg.IsBasicAuthEnabled() {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
)
return return
} }
@@ -271,17 +284,13 @@ func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(logic.ToReturnUser(u)) json.NewEncoder(w).Encode(logic.ToReturnUser(u))
} }
// swagger:route POST /api/users/adm/transfersuperadmin user transferSuperAdmin // @Summary Transfer super admin role to another admin user
// // @Router /api/users/adm/transfersuperadmin/{username} [post]
// Transfers superadmin role to an admin user. // @Tags Users
// // @Param username path string true "Username of the user to transfer super admin role"
// Schemes: https // @Success 200 {object} models.User
// // @Failure 403 {object} models.ErrorResponse
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: userBodyResponse
func transferSuperAdmin(w http.ResponseWriter, r *http.Request) { func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
caller, err := logic.GetUser(r.Header.Get("user")) caller, err := logic.GetUser(r.Header.Get("user"))
@@ -289,7 +298,14 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
} }
if !caller.IsSuperAdmin { if !caller.IsSuperAdmin {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can assign the superadmin role to another user"), "forbidden")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("only superadmin can assign the superadmin role to another user"),
"forbidden",
),
)
return return
} }
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -301,11 +317,22 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
return return
} }
if !u.IsAdmin { if !u.IsAdmin {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("only admins can be promoted to superadmin role"),
"forbidden",
),
)
return return
} }
if !servercfg.IsBasicAuthEnabled() { if !servercfg.IsBasicAuthEnabled() {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
)
return return
} }
@@ -329,17 +356,15 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(logic.ToReturnUser(*u)) json.NewEncoder(w).Encode(logic.ToReturnUser(*u))
} }
// swagger:route POST /api/users/{username} user createUser // @Summary Create a user
// // @Router /api/users/{username} [post]
// Create a user. // @Tags Users
// // @Param username path string true "Username of the user to create"
// Schemes: https // @Param body body models.User true "User details"
// // @Success 200 {object} models.User
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 403 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: userBodyResponse
func createUser(w http.ResponseWriter, r *http.Request) { func createUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
caller, err := logic.GetUser(r.Header.Get("user")) caller, err := logic.GetUser(r.Header.Get("user"))
@@ -368,7 +393,14 @@ func createUser(w http.ResponseWriter, r *http.Request) {
return return
} }
if !servercfg.IsPro && !user.IsAdmin { if !servercfg.IsPro && !user.IsAdmin {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("non-admins users can only be created on Pro version"), "forbidden")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("non-admins users can only be created on Pro version"),
"forbidden",
),
)
return return
} }
@@ -382,17 +414,15 @@ func createUser(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(logic.ToReturnUser(user)) json.NewEncoder(w).Encode(logic.ToReturnUser(user))
} }
// swagger:route PUT /api/users/{username} user updateUser // @Summary Update a user
// // @Router /api/users/{username} [put]
// Update a user. // @Tags Users
// // @Param username path string true "Username of the user to update"
// Schemes: https // @Param body body models.User true "User details"
// // @Success 200 {object} models.User
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 403 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: userBodyResponse
func updateUser(w http.ResponseWriter, r *http.Request) { func updateUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -426,7 +456,14 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
return return
} }
if user.UserName != userchange.UserName { if user.UserName != userchange.UserName {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user in param and request body not matching"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("user in param and request body not matching"),
"badrequest",
),
)
return return
} }
selfUpdate := false selfUpdate := false
@@ -436,23 +473,64 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
if !ismaster && !selfUpdate { if !ismaster && !selfUpdate {
if caller.IsAdmin && user.IsSuperAdmin { if caller.IsAdmin && user.IsSuperAdmin {
slog.Error("non-superadmin user", "caller", caller.UserName, "attempted to update superadmin user", username) slog.Error(
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden")) "non-superadmin user",
"caller",
caller.UserName,
"attempted to update superadmin user",
username,
)
logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"),
)
return return
} }
if !caller.IsAdmin && !caller.IsSuperAdmin { if !caller.IsAdmin && !caller.IsSuperAdmin {
slog.Error("operation not allowed", "caller", caller.UserName, "attempted to update user", username) slog.Error(
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden")) "operation not allowed",
"caller",
caller.UserName,
"attempted to update user",
username,
)
logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"),
)
return return
} }
if caller.IsAdmin && user.IsAdmin { if caller.IsAdmin && user.IsAdmin {
slog.Error("admin user cannot update another admin", "caller", caller.UserName, "attempted to update admin user", username) slog.Error(
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("admin user cannot update another admin"), "forbidden")) "admin user cannot update another admin",
"caller",
caller.UserName,
"attempted to update admin user",
username,
)
logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("admin user cannot update another admin"),
"forbidden",
),
)
return return
} }
if caller.IsAdmin && userchange.IsAdmin { if caller.IsAdmin && userchange.IsAdmin {
err = errors.New("admin user cannot update role of an another user to admin") err = errors.New("admin user cannot update role of an another user to admin")
slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err) slog.Error(
"failed to update user",
"caller",
caller.UserName,
"attempted to update user",
username,
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
return return
} }
@@ -460,16 +538,39 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
} }
if !ismaster && selfUpdate { if !ismaster && selfUpdate {
if user.IsAdmin != userchange.IsAdmin || user.IsSuperAdmin != userchange.IsSuperAdmin { if user.IsAdmin != userchange.IsAdmin || user.IsSuperAdmin != userchange.IsSuperAdmin {
slog.Error("user cannot change his own role", "caller", caller.UserName, "attempted to update user role", username) slog.Error(
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden")) "user cannot change his own role",
"caller",
caller.UserName,
"attempted to update user role",
username,
)
logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"),
)
return return
} }
} }
if ismaster { if ismaster {
if !user.IsSuperAdmin && userchange.IsSuperAdmin { if !user.IsSuperAdmin && userchange.IsSuperAdmin {
slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username) slog.Error(
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden")) "operation not allowed",
"caller",
logic.MasterUser,
"attempted to update user role to superadmin",
username,
)
logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("attempted to update user role to superadmin"),
"forbidden",
),
)
return return
} }
} }
@@ -491,17 +592,12 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(logic.ToReturnUser(*user)) json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
} }
// swagger:route DELETE /api/users/{username} user deleteUser // @Summary Delete a user
// // @Router /api/users/{username} [delete]
// Delete a user. // @Tags Users
// // @Param username path string true "Username of the user to delete"
// Schemes: https // @Success 200 {string} string
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func deleteUser(w http.ResponseWriter, r *http.Request) { func deleteUser(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -523,14 +619,30 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
if user.IsSuperAdmin { if user.IsSuperAdmin {
slog.Error( slog.Error(
"failed to delete user: ", "user", username, "error", "superadmin cannot be deleted") "failed to delete user: ", "user", username, "error", "superadmin cannot be deleted")
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal"),
)
return return
} }
if !caller.IsSuperAdmin { if !caller.IsSuperAdmin {
if caller.IsAdmin && user.IsAdmin { if caller.IsAdmin && user.IsAdmin {
slog.Error( slog.Error(
"failed to delete user: ", "user", username, "error", "admin cannot delete another admin user, including oneself") "failed to delete user: ",
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("admin cannot delete another admin user, including oneself"), "internal")) "user",
username,
"error",
"admin cannot delete another admin user, including oneself",
)
logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("admin cannot delete another admin user, including oneself"),
"internal",
),
)
return return
} }
} }
@@ -586,17 +698,11 @@ func socketHandler(w http.ResponseWriter, r *http.Request) {
go auth.SessionHandler(conn) go auth.SessionHandler(conn)
} }
// swagger:route GET /api/users_pending user getPendingUsers // @Summary Get all pending users
// // @Router /api/users_pending [get]
// Get all pending users. // @Tags Users
// // @Success 200 {array} models.User
// Schemes: https // @Failure 500 {object} models.ErrorResponse
//
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func getPendingUsers(w http.ResponseWriter, r *http.Request) { func getPendingUsers(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -613,17 +719,12 @@ func getPendingUsers(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(users) json.NewEncoder(w).Encode(users)
} }
// swagger:route POST /api/users_pending/user/{username} user approvePendingUser // @Summary Approve a pending user
// // @Router /api/users_pending/user/{username} [post]
// approve pending user. // @Tags Users
// // @Param username path string true "Username of the pending user to approve"
// Schemes: https // @Success 200 {string} string
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func approvePendingUser(w http.ResponseWriter, r *http.Request) { func approvePendingUser(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -647,12 +748,23 @@ func approvePendingUser(w http.ResponseWriter, r *http.Request) {
UserName: user.UserName, UserName: user.UserName,
Password: newPass, Password: newPass,
}); err != nil { }); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create user: %s", err), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("failed to create user: %s", err), "internal"),
)
return return
} }
err = logic.DeletePendingUser(username) err = logic.DeletePendingUser(username)
if err != nil { if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to delete pending user: %s", err),
"internal",
),
)
return return
} }
break break
@@ -661,17 +773,12 @@ func approvePendingUser(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponse(w, r, "approved "+username) logic.ReturnSuccessResponse(w, r, "approved "+username)
} }
// swagger:route DELETE /api/users_pending/user/{username} user deletePendingUser // @Summary Delete a pending user
// // @Router /api/users_pending/user/{username} [delete]
// delete pending user. // @Tags Users
// // @Param username path string true "Username of the pending user to delete"
// Schemes: https // @Success 200 {string} string
// // @Failure 500 {object} models.ErrorResponse
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func deletePendingUser(w http.ResponseWriter, r *http.Request) { func deletePendingUser(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -688,7 +795,14 @@ func deletePendingUser(w http.ResponseWriter, r *http.Request) {
if user.UserName == username { if user.UserName == username {
err = logic.DeletePendingUser(username) err = logic.DeletePendingUser(username)
if err != nil { if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to delete pending user: %s", err),
"internal",
),
)
return return
} }
break break
@@ -697,23 +811,24 @@ func deletePendingUser(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponse(w, r, "deleted pending "+username) logic.ReturnSuccessResponse(w, r, "deleted pending "+username)
} }
// swagger:route DELETE /api/users_pending/{username}/pending user deleteAllPendingUsers // @Summary Delete all pending users
// // @Router /api/users_pending [delete]
// delete all pending users. // @Tags Users
// // @Success 200 {string} string
// Schemes: https // @Failure 500 {object} models.ErrorResponse
//
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func deleteAllPendingUsers(w http.ResponseWriter, r *http.Request) { func deleteAllPendingUsers(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
err := database.DeleteAllRecords(database.PENDING_USERS_TABLE_NAME) err := database.DeleteAllRecords(database.PENDING_USERS_TABLE_NAME)
if err != nil { if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending users "+err.Error()), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("failed to delete all pending users "+err.Error()),
"internal",
),
)
return return
} }
logic.ReturnSuccessResponse(w, r, "cleared all pending users") logic.ReturnSuccessResponse(w, r, "cleared all pending users")

1
docs/APIUsage.md Normal file
View File

@@ -0,0 +1 @@
Most actions that can be performed via API can be performed via UI. We recommend managing your networks using the official netmaker-ui project. However, Netmaker can also be run without the UI, and all functions can be achieved via API calls. If your use case requires using Netmaker without the UI or you need to do some troubleshooting/advanced configuration, using the API directly may help.

10
docs/Authentication.md Normal file
View File

@@ -0,0 +1,10 @@
API calls are primarily authenticated using a user authentication token. This token should be included in the header as follows:
-H "Authorization: Bearer <YOUR_AUTH_TOKEN>"
To obtain YOUR_AUTH_TOKEN:
Call the api/users/adm/authenticate endpoint (see documentation below for details).
Note: While a MasterKey exists (configurable via env var or config file), it should be considered a backup option, used only when server access is lost. By default, this key is "secret key," but it's crucial to change this and keep it secure in your instance.
For more information on configuration and security best practices, refer to the [Netmaker documentation](https://docs.netmaker.org/index.html).

1
docs/Pricing.md Normal file
View File

@@ -0,0 +1 @@
Check out our [Pricing](https://www.netmaker.io/pricing). And Feel Free to [Contact Us](https://www.netmaker.io/contact) if you have any questions or need some clarifications.

38
main.go
View File

@@ -29,6 +29,17 @@ import (
var version = "v0.25.0" var version = "v0.25.0"
// @title NetMaker
// @version 0.24.3
// @description NetMaker API Docs
// @tag.name APIUsage
// @tag.description.markdown
// @tag.name Authentication
// @tag.description.markdown
// @tag.name Pricing
// @tag.description.markdown
// @host api.demo.netmaker.io
// Start DB Connection and start API Request Handler // Start DB Connection and start API Request Handler
func main() { func main() {
absoluteConfigPath := flag.String("c", "", "absolute path to configuration file") absoluteConfigPath := flag.String("c", "", "absolute path to configuration file")
@@ -135,7 +146,10 @@ func startControllers(wg *sync.WaitGroup, ctx context.Context) {
} }
if !servercfg.IsRestBackend() && !servercfg.IsMessageQueueBackend() { if !servercfg.IsRestBackend() && !servercfg.IsMessageQueueBackend() {
logger.Log(0, "No Server Mode selected, so nothing is being served! Set Rest mode (REST_BACKEND) or MessageQueue (MESSAGEQUEUE_BACKEND) to 'true'.") logger.Log(
0,
"No Server Mode selected, so nothing is being served! Set Rest mode (REST_BACKEND) or MessageQueue (MESSAGEQUEUE_BACKEND) to 'true'.",
)
} }
wg.Add(1) wg.Add(1)
@@ -167,10 +181,21 @@ func runMessageQueue(wg *sync.WaitGroup, ctx context.Context) {
node.Action = models.NODE_DELETE node.Action = models.NODE_DELETE
node.PendingDelete = true node.PendingDelete = true
if err := mq.NodeUpdate(node); err != nil { if err := mq.NodeUpdate(node); err != nil {
logger.Log(0, "failed to send peer update for deleted node: ", node.ID.String(), err.Error()) logger.Log(
0,
"failed to send peer update for deleted node: ",
node.ID.String(),
err.Error(),
)
} }
if err := logic.DeleteNode(node, true); err != nil { if err := logic.DeleteNode(node, true); err != nil {
slog.Error("error deleting expired node", "nodeid", node.ID.String(), "error", err.Error()) slog.Error(
"error deleting expired node",
"nodeid",
node.ID.String(),
"error",
err.Error(),
)
} }
go mq.PublishDeletedNodePeerUpdate(node) go mq.PublishDeletedNodePeerUpdate(node)
} }
@@ -189,7 +214,12 @@ func setVerbosity() {
} }
return a return a
} }
logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{AddSource: true, ReplaceAttr: replace, Level: logLevel})) logger := slog.New(
slog.NewJSONHandler(
os.Stderr,
&slog.HandlerOptions{AddSource: true, ReplaceAttr: replace, Level: logLevel},
),
)
slog.SetDefault(logger) slog.SetDefault(logger)
switch verbose { switch verbose {
case 4: case 4:

View File

@@ -55,8 +55,8 @@ type CommonNode struct {
ID uuid.UUID `json:"id" yaml:"id"` ID uuid.UUID `json:"id" yaml:"id"`
HostID uuid.UUID `json:"hostid" yaml:"hostid"` HostID uuid.UUID `json:"hostid" yaml:"hostid"`
Network string `json:"network" yaml:"network"` Network string `json:"network" yaml:"network"`
NetworkRange net.IPNet `json:"networkrange" yaml:"networkrange"` NetworkRange net.IPNet `json:"networkrange" yaml:"networkrange" swaggertype:"primitive,integer"`
NetworkRange6 net.IPNet `json:"networkrange6" yaml:"networkrange6"` NetworkRange6 net.IPNet `json:"networkrange6" yaml:"networkrange6" swaggertype:"primitive,number"`
Server string `json:"server" yaml:"server"` Server string `json:"server" yaml:"server"`
Connected bool `json:"connected" yaml:"connected"` Connected bool `json:"connected" yaml:"connected"`
Address net.IPNet `json:"address" yaml:"address"` Address net.IPNet `json:"address" yaml:"address"`
@@ -64,11 +64,11 @@ type CommonNode struct {
Action string `json:"action" yaml:"action"` Action string `json:"action" yaml:"action"`
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"` LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"` IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"`
EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"` EgressGatewayRanges []string `json:"egressgatewayranges" yaml:"egressgatewayranges" bson:"egressgatewayranges"`
IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"` IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"`
IsRelayed bool `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"` IsRelayed bool `json:"isrelayed" yaml:"isrelayed" bson:"isrelayed"`
RelayedBy string `json:"relayedby" bson:"relayedby" yaml:"relayedby"` RelayedBy string `json:"relayedby" yaml:"relayedby" bson:"relayedby"`
IsRelay bool `json:"isrelay" bson:"isrelay" yaml:"isrelay"` IsRelay bool `json:"isrelay" yaml:"isrelay" bson:"isrelay"`
RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"` RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"`
IngressDNS string `json:"ingressdns" yaml:"ingressdns"` IngressDNS string `json:"ingressdns" yaml:"ingressdns"`
DNSOn bool `json:"dnson" yaml:"dnson"` DNSOn bool `json:"dnson" yaml:"dnson"`
@@ -96,7 +96,7 @@ type Node struct {
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"` IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"` InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"` InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
AdditionalRagIps []net.IP `json:"additional_rag_ips" yaml:"additional_rag_ips"` AdditionalRagIps []net.IP `json:"additional_rag_ips" yaml:"additional_rag_ips" swaggertype:"array,number"`
} }
// LegacyNode - legacy struct for node model // LegacyNode - legacy struct for node model
@@ -375,7 +375,10 @@ func (node *LegacyNode) SetDefaultFailover() {
} }
// Node.Fill - fills other node data into calling node data if not set on calling node (skips DNSOn) // Node.Fill - fills other node data into calling node data if not set on calling node (skips DNSOn)
func (newNode *Node) Fill(currentNode *Node, isPro bool) { // TODO add new field for nftables present func (newNode *Node) Fill(
currentNode *Node,
isPro bool,
) { // TODO add new field for nftables present
newNode.ID = currentNode.ID newNode.ID = currentNode.ID
newNode.HostID = currentNode.HostID newNode.HostID = currentNode.HostID
// Revisit the logic for boolean values // Revisit the logic for boolean values

View File

@@ -19,24 +19,25 @@ import (
// FailOverHandlers - handlers for FailOver // FailOverHandlers - handlers for FailOver
func FailOverHandlers(r *mux.Router) { func FailOverHandlers(r *mux.Router) {
r.HandleFunc("/api/v1/node/{nodeid}/failover", http.HandlerFunc(getfailOver)).Methods(http.MethodGet) r.HandleFunc("/api/v1/node/{nodeid}/failover", http.HandlerFunc(getfailOver)).
r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(createfailOver))).Methods(http.MethodPost) Methods(http.MethodGet)
r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(deletefailOver))).Methods(http.MethodDelete) r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(createfailOver))).
r.HandleFunc("/api/v1/node/{network}/failover/reset", logic.SecurityCheck(true, http.HandlerFunc(resetFailOver))).Methods(http.MethodPost) Methods(http.MethodPost)
r.HandleFunc("/api/v1/node/{nodeid}/failover_me", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).Methods(http.MethodPost) r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(deletefailOver))).
Methods(http.MethodDelete)
r.HandleFunc("/api/v1/node/{network}/failover/reset", logic.SecurityCheck(true, http.HandlerFunc(resetFailOver))).
Methods(http.MethodPost)
r.HandleFunc("/api/v1/node/{nodeid}/failover_me", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).
Methods(http.MethodPost)
} }
// swagger:route GET /api/v1/node/failover node getfailOver // @Summary Get failover node
// // @Router /api/v1/node/{nodeid}/failover [get]
// get failover node. // @Tags PRO
// // @Param nodeid path string true "Node ID"
// Schemes: https // @Success 200 {object} models.Node
// // @Failure 400 {object} models.ErrorResponse
// Security: // @Failure 404 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: nodeResponse
func getfailOver(w http.ResponseWriter, r *http.Request) { func getfailOver(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
nodeid := params["nodeid"] nodeid := params["nodeid"]
@@ -50,24 +51,24 @@ func getfailOver(w http.ResponseWriter, r *http.Request) {
failOverNode, exists := proLogic.FailOverExists(node.Network) failOverNode, exists := proLogic.FailOverExists(node.Network)
if !exists { if !exists {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failover node not found"), "notfound")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("failover node not found"), "notfound"),
)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
logic.ReturnSuccessResponseWithJson(w, r, failOverNode, "get failover node successfully") logic.ReturnSuccessResponseWithJson(w, r, failOverNode, "get failover node successfully")
} }
// swagger:route POST /api/v1/node/failover node createfailOver // @Summary Create failover node
// // @Router /api/v1/node/{nodeid}/failover [post]
// Create a relay. // @Tags PRO
// // @Param nodeid path string true "Node ID"
// Schemes: https // @Success 200 {object} models.Node
// // @Failure 400 {object} models.ErrorResponse
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: nodeResponse
func createfailOver(w http.ResponseWriter, r *http.Request) { func createfailOver(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
nodeid := params["nodeid"] nodeid := params["nodeid"]
@@ -88,6 +89,12 @@ func createfailOver(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponseWithJson(w, r, node, "created failover successfully") logic.ReturnSuccessResponseWithJson(w, r, node, "created failover successfully")
} }
// @Summary Reset failover for a network
// @Router /api/v1/node/{network}/failover/reset [post]
// @Tags PRO
// @Param network path string true "Network ID"
// @Success 200 {object} models.SuccessResponse
// @Failure 500 {object} models.ErrorResponse
func resetFailOver(w http.ResponseWriter, r *http.Request) { func resetFailOver(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
net := params["network"] net := params["network"]
@@ -108,17 +115,13 @@ func resetFailOver(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponse(w, r, "failover has been reset successfully") logic.ReturnSuccessResponse(w, r, "failover has been reset successfully")
} }
// swagger:route DELETE /api/v1/node/failover node deletefailOver // @Summary Delete failover node
// // @Router /api/v1/node/{nodeid}/failover [delete]
// Create a relay. // @Tags PRO
// // @Param nodeid path string true "Node ID"
// Schemes: https // @Success 200 {object} models.Node
// // @Failure 400 {object} models.ErrorResponse
// Security: // @Failure 500 {object} models.ErrorResponse
// oauth
//
// Responses:
// 200: nodeResponse
func deletefailOver(w http.ResponseWriter, r *http.Request) { func deletefailOver(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
nodeid := params["nodeid"] nodeid := params["nodeid"]
@@ -145,17 +148,15 @@ func deletefailOver(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponseWithJson(w, r, node, "deleted failover successfully") logic.ReturnSuccessResponseWithJson(w, r, node, "deleted failover successfully")
} }
// swagger:route POST /api/node/{nodeid}/failOverME node failOver_me // @Summary Failover me
// // @Router /api/v1/node/{nodeid}/failover_me [post]
// Create a relay. // @Tags PRO
// // @Param nodeid path string true "Node ID"
// Schemes: https // @Accept json
// // @Param body body models.FailOverMeReq true "Failover request"
// Security: // @Success 200 {object} models.SuccessResponse
// oauth // @Failure 400 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: nodeResponse
func failOverME(w http.ResponseWriter, r *http.Request) { func failOverME(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
nodeid := params["nodeid"] nodeid := params["nodeid"]
@@ -174,7 +175,14 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
failOverNode, exists := proLogic.FailOverExists(node.Network) failOverNode, exists := proLogic.FailOverExists(node.Network)
if !exists { if !exists {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("req-from: %s, failover node doesn't exist in the network", host.Name), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("req-from: %s, failover node doesn't exist in the network", host.Name),
"badrequest",
),
)
return return
} }
var failOverReq models.FailOverMeReq var failOverReq models.FailOverMeReq
@@ -188,27 +196,57 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
peerNode, err := logic.GetNodeByID(failOverReq.NodeID) peerNode, err := logic.GetNodeByID(failOverReq.NodeID)
if err != nil { if err != nil {
slog.Error("peer not found: ", "nodeid", failOverReq.NodeID, "error", err) slog.Error("peer not found: ", "nodeid", failOverReq.NodeID, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("peer not found"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("peer not found"), "badrequest"),
)
return return
} }
if node.IsFailOver { if node.IsFailOver {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is acting as failover"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("node is acting as failover"), "badrequest"),
)
return return
} }
if node.IsRelayed && node.RelayedBy == peerNode.ID.String() { if node.IsRelayed && node.RelayedBy == peerNode.ID.String() {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is relayed by peer node"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("node is relayed by peer node"), "badrequest"),
)
return return
} }
if node.IsRelay && peerNode.RelayedBy == node.ID.String() { if node.IsRelay && peerNode.RelayedBy == node.ID.String() {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as relay for the peer node"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("node acting as relay for the peer node"), "badrequest"),
)
return return
} }
if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() { if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as internet gw for the peer node"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("node acting as internet gw for the peer node"),
"badrequest",
),
)
return return
} }
if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() { if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node using a internet gw by the peer node"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("node using a internet gw by the peer node"),
"badrequest",
),
)
return return
} }
@@ -216,10 +254,20 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
slog.Error("failed to create failover", "id", node.ID.String(), slog.Error("failed to create failover", "id", node.ID.String(),
"network", node.Network, "error", err) "network", node.Network, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create failover: %v", err), "internal")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("failed to create failover: %v", err), "internal"),
)
return return
} }
slog.Info("[auto-relay] created relay on node", "node", node.ID.String(), "network", node.Network) slog.Info(
"[auto-relay] created relay on node",
"node",
node.ID.String(),
"network",
node.Network,
)
sendPeerUpdate = true sendPeerUpdate = true
if sendPeerUpdate { if sendPeerUpdate {

View File

@@ -16,22 +16,24 @@ import (
// InetHandlers - handlers for internet gw // InetHandlers - handlers for internet gw
func InetHandlers(r *mux.Router) { func InetHandlers(r *mux.Router) {
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(createInternetGw))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(createInternetGw))).
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(updateInternetGw))).Methods(http.MethodPut) Methods(http.MethodPost)
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(deleteInternetGw))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(updateInternetGw))).
Methods(http.MethodPut)
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(deleteInternetGw))).
Methods(http.MethodDelete)
} }
// swagger:route POST /api/nodes/{network}/{nodeid}/inet_gw nodes createInternetGw // @Summary Create an internet gateway
// // @Router /api/nodes/{network}/{nodeid}/inet_gw [post]
// Create an inet node. // @Tags PRO
// // @Accept json
// Schemes: https // @Param network path string true "Network ID"
// // @Param nodeid path string true "Node ID"
// Security: // @Param body body models.InetNodeReq true "Internet gateway request"
// oauth // @Success 200 {object} models.Node
// // @Failure 400 {object} models.ErrorResponse
// Responses: // @Failure 500 {object} models.ErrorResponse
// 200: nodeResponse
func createInternetGw(w http.ResponseWriter, r *http.Request) { func createInternetGw(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -58,7 +60,14 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
return return
} }
if host.OS != models.OS_Types.Linux { if host.OS != models.OS_Types.Linux {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only linux nodes can be made internet gws"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("only linux nodes can be made internet gws"),
"badrequest",
),
)
return return
} }
err = proLogic.ValidateInetGwReq(node, request, false) err = proLogic.ValidateInetGwReq(node, request, false)
@@ -81,23 +90,29 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
return return
} }
apiNode := node.ConvertToAPINode() apiNode := node.ConvertToAPINode()
logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid) logger.Log(
1,
r.Header.Get("user"),
"created ingress gateway on node",
nodeid,
"on network",
netid,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
go mq.PublishPeerUpdate(false) go mq.PublishPeerUpdate(false)
} }
// swagger:route PUT /api/nodes/{network}/{nodeid}/inet_gw nodes updateInternetGw // @Summary Update an internet gateway
// // @Router /api/nodes/{network}/{nodeid}/inet_gw [put]
// update an inet node. // @Tags PRO
// // @Accept json
// Schemes: https // @Param network path string true "Network ID"
// // @Param nodeid path string true "Node ID"
// Security: // @Param body body models.InetNodeReq true "Internet gateway request"
// oauth // @Success 200 {object} models.Node
// // @Failure 400 {object} models.ErrorResponse
// Responses: // @Failure 500 {object} models.ErrorResponse
// 200: nodeResponse
func updateInternetGw(w http.ResponseWriter, r *http.Request) { func updateInternetGw(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -115,7 +130,11 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
return return
} }
if !node.IsInternetGateway { if !node.IsInternetGateway {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is not a internet gw"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("node is not a internet gw"), "badrequest"),
)
return return
} }
err = proLogic.ValidateInetGwReq(node, request, true) err = proLogic.ValidateInetGwReq(node, request, true)
@@ -131,23 +150,27 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
return return
} }
apiNode := node.ConvertToAPINode() apiNode := node.ConvertToAPINode()
logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid) logger.Log(
1,
r.Header.Get("user"),
"created ingress gateway on node",
nodeid,
"on network",
netid,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
go mq.PublishPeerUpdate(false) go mq.PublishPeerUpdate(false)
} }
// swagger:route DELETE /api/nodes/{network}/{nodeid}/inet_gw nodes deleteInternetGw // @Summary Delete an internet gateway
// // @Router /api/nodes/{network}/{nodeid}/inet_gw [delete]
// Delete an internet gw. // @Tags PRO
// // @Param network path string true "Network ID"
// Schemes: https // @Param nodeid path string true "Node ID"
// // @Success 200 {object} models.Node
// Security: // @Failure 400 {object} models.ErrorResponse
// oauth // @Failure 500 {object} models.ErrorResponse
//
// Responses:
// 200: nodeResponse
func deleteInternetGw(w http.ResponseWriter, r *http.Request) { func deleteInternetGw(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -166,7 +189,14 @@ func deleteInternetGw(w http.ResponseWriter, r *http.Request) {
return return
} }
apiNode := node.ConvertToAPINode() apiNode := node.ConvertToAPINode()
logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid) logger.Log(
1,
r.Header.Get("user"),
"created ingress gateway on node",
nodeid,
"on network",
netid,
)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
go mq.PublishPeerUpdate(false) go mq.PublishPeerUpdate(false)

View File

@@ -19,22 +19,25 @@ import (
// RelayHandlers - handle Pro Relays // RelayHandlers - handle Pro Relays
func RelayHandlers(r *mux.Router) { func RelayHandlers(r *mux.Router) {
r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", controller.Authorize(false, true, "user", http.HandlerFunc(createRelay))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", controller.Authorize(false, true, "user", http.HandlerFunc(createRelay))).
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", controller.Authorize(false, true, "user", http.HandlerFunc(deleteRelay))).Methods(http.MethodDelete) Methods(http.MethodPost)
r.HandleFunc("/api/v1/host/{hostid}/failoverme", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", controller.Authorize(false, true, "user", http.HandlerFunc(deleteRelay))).
Methods(http.MethodDelete)
r.HandleFunc("/api/v1/host/{hostid}/failoverme", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).
Methods(http.MethodPost)
} }
// swagger:route POST /api/nodes/{network}/{nodeid}/createrelay nodes createRelay // @Summary Create a relay
// // @Router /api/nodes/{network}/{nodeid}/createrelay [post]
// Create a relay. // @Tags PRO
// // @Accept json
// Schemes: https // @Produce json
// // @Param network path string true "Network ID"
// Security: // @Param nodeid path string true "Node ID"
// oauth // @Param body body models.RelayRequest true "Relay request parameters"
// // @Success 200 {object} models.ApiNode
// Responses: // @Failure 400 {object} models.ErrorResponse
// 200: nodeResponse // @Failure 500 {object} models.ErrorResponse
func createRelay(w http.ResponseWriter, r *http.Request) { func createRelay(w http.ResponseWriter, r *http.Request) {
var relayRequest models.RelayRequest var relayRequest models.RelayRequest
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -49,8 +52,16 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
relayRequest.NodeID = params["nodeid"] relayRequest.NodeID = params["nodeid"]
_, relayNode, err := proLogic.CreateRelay(relayRequest) _, relayNode, err := proLogic.CreateRelay(relayRequest)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(
fmt.Sprintf("failed to create relay on node [%s] on network [%s]: %v", relayRequest.NodeID, relayRequest.NetID, err)) 0,
r.Header.Get("user"),
fmt.Sprintf(
"failed to create relay on node [%s] on network [%s]: %v",
relayRequest.NodeID,
relayRequest.NetID,
err,
),
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
@@ -64,23 +75,29 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
} }
} }
go mq.PublishPeerUpdate(false) go mq.PublishPeerUpdate(false)
logger.Log(1, r.Header.Get("user"), "created relay on node", relayRequest.NodeID, "on network", relayRequest.NetID) logger.Log(
1,
r.Header.Get("user"),
"created relay on node",
relayRequest.NodeID,
"on network",
relayRequest.NetID,
)
apiNode := relayNode.ConvertToAPINode() apiNode := relayNode.ConvertToAPINode()
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)
} }
// swagger:route DELETE /api/nodes/{network}/{nodeid}/deleterelay nodes deleteRelay // @Summary Remove a relay
// // @Router /api/nodes/{network}/{nodeid}/deleterelay [delete]
// Remove a relay. // @Tags PRO
// // @Accept json
// Schemes: https // @Produce json
// // @Param network path string true "Network ID"
// Security: // @Param nodeid path string true "Node ID"
// oauth // @Success 200 {object} models.ApiNode
// // @Failure 400 {object} models.ErrorResponse
// Responses: // @Failure 500 {object} models.ErrorResponse
// 200: nodeResponse
func deleteRelay(w http.ResponseWriter, r *http.Request) { func deleteRelay(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -97,7 +114,15 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
for _, relayedNode := range updateNodes { for _, relayedNode := range updateNodes {
err = mq.NodeUpdate(&relayedNode) err = mq.NodeUpdate(&relayedNode)
if err != nil { if err != nil {
logger.Log(1, "relayed node update ", relayedNode.ID.String(), "on network", relayedNode.Network, ": ", err.Error()) logger.Log(
1,
"relayed node update ",
relayedNode.ID.String(),
"on network",
relayedNode.Network,
": ",
err.Error(),
)
} }
h, err := logic.GetHost(relayedNode.HostID.String()) h, err := logic.GetHost(relayedNode.HostID.String())
@@ -109,14 +134,27 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
} }
node.IsRelay = true // for iot update to recognise that it has to delete relay peer node.IsRelay = true // for iot update to recognise that it has to delete relay peer
if err = mq.PublishSingleHostPeerUpdate(h, nodes, &node, nil, false); err != nil { if err = mq.PublishSingleHostPeerUpdate(h, nodes, &node, nil, false); err != nil {
logger.Log(1, "failed to publish peer update to host", h.ID.String(), ": ", err.Error()) logger.Log(
1,
"failed to publish peer update to host",
h.ID.String(),
": ",
err.Error(),
)
} }
} }
} }
} }
mq.PublishPeerUpdate(false) mq.PublishPeerUpdate(false)
}() }()
logger.Log(1, r.Header.Get("user"), "deleted relay on node", node.ID.String(), "on network", node.Network) logger.Log(
1,
r.Header.Get("user"),
"deleted relay on node",
node.ID.String(),
"on network",
node.Network,
)
apiNode := node.ConvertToAPINode() apiNode := node.ConvertToAPINode()
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(apiNode) json.NewEncoder(w).Encode(apiNode)

View File

@@ -17,27 +17,30 @@ import (
) )
func UserHandlers(r *mux.Router) { func UserHandlers(r *mux.Router) {
r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).Methods(http.MethodPost) r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).
r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).Methods(http.MethodDelete) Methods(http.MethodPost)
r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserRemoteAccessGws)))).Methods(http.MethodGet) r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).
r.HandleFunc("/api/users/ingress/{ingress_id}", logic.SecurityCheck(true, http.HandlerFunc(ingressGatewayUsers))).Methods(http.MethodGet) Methods(http.MethodDelete)
r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserRemoteAccessGws)))).
Methods(http.MethodGet)
r.HandleFunc("/api/users/ingress/{ingress_id}", logic.SecurityCheck(true, http.HandlerFunc(ingressGatewayUsers))).
Methods(http.MethodGet)
r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods(http.MethodGet) r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods(http.MethodGet)
r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods(http.MethodGet) r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods(http.MethodGet)
r.HandleFunc("/api/oauth/headless", auth.HandleHeadlessSSO) r.HandleFunc("/api/oauth/headless", auth.HandleHeadlessSSO)
r.HandleFunc("/api/oauth/register/{regKey}", auth.RegisterHostSSO).Methods(http.MethodGet) r.HandleFunc("/api/oauth/register/{regKey}", auth.RegisterHostSSO).Methods(http.MethodGet)
} }
// swagger:route POST /api/users/{username}/remote_access_gw user attachUserToRemoteAccessGateway // @Summary Attach user to a remote access gateway
// // @Router /api/users/{username}/remote_access_gw/{remote_access_gateway_id} [post]
// Attach User to a remote access gateway. // @Tags PRO
// // @Accept json
// Schemes: https // @Produce json
// // @Param username path string true "Username"
// Security: // @Param remote_access_gateway_id path string true "Remote Access Gateway ID"
// oauth // @Success 200 {object} models.ReturnUser
// // @Failure 400 {object} models.ErrorResponse
// Responses: // @Failure 500 {object} models.ErrorResponse
// 200: userBodyResponse
func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) { func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -46,27 +49,59 @@ func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
username := params["username"] username := params["username"]
remoteGwID := params["remote_access_gateway_id"] remoteGwID := params["remote_access_gateway_id"]
if username == "" || remoteGwID == "" { if username == "" || remoteGwID == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params `username` and `remote_access_gateway_id`"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("required params `username` and `remote_access_gateway_id`"),
"badrequest",
),
)
return return
} }
user, err := logic.GetUser(username) user, err := logic.GetUser(username)
if err != nil { if err != nil {
slog.Error("failed to fetch user: ", "username", username, "error", err.Error()) slog.Error("failed to fetch user: ", "username", username, "error", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to fetch user %s, error: %v", username, err),
"badrequest",
),
)
return return
} }
if user.IsAdmin || user.IsSuperAdmin { if user.IsAdmin || user.IsSuperAdmin {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("superadmins/admins have access to all gateways"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("superadmins/admins have access to all gateways"),
"badrequest",
),
)
return return
} }
node, err := logic.GetNodeByID(remoteGwID) node, err := logic.GetNodeByID(remoteGwID)
if err != nil { if err != nil {
slog.Error("failed to fetch gateway node", "nodeID", remoteGwID, "error", err) slog.Error("failed to fetch gateway node", "nodeID", remoteGwID, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch remote access gateway node, error: %v", err), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to fetch remote access gateway node, error: %v", err),
"badrequest",
),
)
return return
} }
if !node.IsIngressGateway { if !node.IsIngressGateway {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("node is not a remote access gateway"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(fmt.Errorf("node is not a remote access gateway"), "badrequest"),
)
return return
} }
if user.RemoteGwIDs == nil { if user.RemoteGwIDs == nil {
@@ -76,24 +111,30 @@ func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
err = logic.UpsertUser(*user) err = logic.UpsertUser(*user)
if err != nil { if err != nil {
slog.Error("failed to update user's gateways", "user", username, "error", err) slog.Error("failed to update user's gateways", "user", username, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch remote access gateway node,error: %v", err), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to fetch remote access gateway node,error: %v", err),
"badrequest",
),
)
return return
} }
json.NewEncoder(w).Encode(logic.ToReturnUser(*user)) json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
} }
// swagger:route DELETE /api/users/{username}/remote_access_gw user removeUserFromRemoteAccessGW // @Summary Remove user from a remote access gateway
// // @Router /api/users/{username}/remote_access_gw/{remote_access_gateway_id} [delete]
// Delete User from a remote access gateway. // @Tags PRO
// // @Accept json
// Schemes: https // @Produce json
// // @Param username path string true "Username"
// Security: // @Param remote_access_gateway_id path string true "Remote Access Gateway ID"
// oauth // @Success 200 {object} models.ReturnUser
// // @Failure 400 {object} models.ErrorResponse
// Responses: // @Failure 500 {object} models.ErrorResponse
// 200: userBodyResponse
func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) { func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -102,13 +143,27 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
username := params["username"] username := params["username"]
remoteGwID := params["remote_access_gateway_id"] remoteGwID := params["remote_access_gateway_id"]
if username == "" || remoteGwID == "" { if username == "" || remoteGwID == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params `username` and `remote_access_gateway_id`"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("required params `username` and `remote_access_gateway_id`"),
"badrequest",
),
)
return return
} }
user, err := logic.GetUser(username) user, err := logic.GetUser(username)
if err != nil { if err != nil {
logger.Log(0, username, "failed to fetch user: ", err.Error()) logger.Log(0, username, "failed to fetch user: ", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to fetch user %s, error: %v", username, err),
"badrequest",
),
)
return return
} }
delete(user.RemoteGwIDs, remoteGwID) delete(user.RemoteGwIDs, remoteGwID)
@@ -139,23 +194,30 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
err = logic.UpsertUser(*user) err = logic.UpsertUser(*user)
if err != nil { if err != nil {
slog.Error("failed to update user gateways", "user", username, "error", err) slog.Error("failed to update user gateways", "user", username, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to fetch remote access gaetway node "+err.Error()), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
errors.New("failed to fetch remote access gaetway node "+err.Error()),
"badrequest",
),
)
return return
} }
json.NewEncoder(w).Encode(logic.ToReturnUser(*user)) json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
} }
// swagger:route GET "/api/users/{username}/remote_access_gw" nodes getUserRemoteAccessGws // @Summary Get user's remote access gateways
// // @Router /api/users/{username}/remote_access_gw [get]
// Get an individual node. // @Tags PRO
// // @Accept json
// Schemes: https // @Produce json
// // @Param username path string true "Username"
// Security: // @Param remote_access_clientid query string false "Remote Access Client ID"
// oauth // @Param from_mobile query boolean false "Request from mobile"
// // @Success 200 {array} models.UserRemoteGws
// Responses: // @Failure 400 {object} models.ErrorResponse
// 200: nodeResponse // @Failure 500 {object} models.ErrorResponse
func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) { func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
// set header. // set header.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -163,7 +225,11 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
username := params["username"] username := params["username"]
if username == "" { if username == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params username"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("required params username"), "badrequest"),
)
return return
} }
remoteAccessClientID := r.URL.Query().Get("remote_access_clientid") remoteAccessClientID := r.URL.Query().Get("remote_access_clientid")
@@ -178,7 +244,11 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
} }
reqFromMobile := r.URL.Query().Get("from_mobile") == "true" reqFromMobile := r.URL.Query().Get("from_mobile") == "true"
if req.RemoteAccessClientID == "" && remoteAccessClientID == "" { if req.RemoteAccessClientID == "" && remoteAccessClientID == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("remote access client id cannot be empty"), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(errors.New("remote access client id cannot be empty"), "badrequest"),
)
return return
} }
if req.RemoteAccessClientID == "" { if req.RemoteAccessClientID == "" {
@@ -188,7 +258,14 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
user, err := logic.GetUser(username) user, err := logic.GetUser(username)
if err != nil { if err != nil {
logger.Log(0, username, "failed to fetch user: ", err.Error()) logger.Log(0, username, "failed to fetch user: ", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest")) logic.ReturnErrorResponse(
w,
r,
logic.FormatError(
fmt.Errorf("failed to fetch user %s, error: %v", username, err),
"badrequest",
),
)
return return
} }
allextClients, err := logic.GetAllExtClients() allextClients, err := logic.GetAllExtClients()
@@ -199,7 +276,8 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
processedAdminNodeIds := make(map[string]struct{}) processedAdminNodeIds := make(map[string]struct{})
for _, extClient := range allextClients { for _, extClient := range allextClients {
if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username { if extClient.RemoteAccessClientID == req.RemoteAccessClientID &&
extClient.OwnerID == username {
node, err := logic.GetNodeByID(extClient.IngressGatewayID) node, err := logic.GetNodeByID(extClient.IngressGatewayID)
if err != nil { if err != nil {
continue continue
@@ -219,7 +297,8 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
slog.Error("failed to get node network", "error", err) slog.Error("failed to get node network", "error", err)
} }
if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) && ok { if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) &&
ok {
gws := userGws[node.Network] gws := userGws[node.Network]
extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient) extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
gws = append(gws, models.UserRemoteGws{ gws = append(gws, models.UserRemoteGws{
@@ -345,17 +424,15 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(userGws) json.NewEncoder(w).Encode(userGws)
} }
// swagger:route GET /api/nodes/{network}/{nodeid}/ingress/users users ingressGatewayUsers // @Summary List users attached to an remote access gateway
// // @Router /api/nodes/{network}/{nodeid}/ingress/users [get]
// Lists all the users attached to an ingress gateway. // @Tags PRO
// // @Accept json
// Schemes: https // @Produce json
// // @Param ingress_id path string true "Ingress Gateway ID"
// Security: // @Success 200 {array} models.IngressGwUsers
// oauth // @Failure 400 {object} models.ErrorResponse
// // @Failure 500 {object} models.ErrorResponse
// Responses:
// 200: nodeResponse
func ingressGatewayUsers(w http.ResponseWriter, r *http.Request) { func ingressGatewayUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -368,8 +445,17 @@ func ingressGatewayUsers(w http.ResponseWriter, r *http.Request) {
} }
gwUsers, err := logic.GetIngressGwUsers(node) gwUsers, err := logic.GetIngressGwUsers(node)
if err != nil { if err != nil {
slog.Error("failed to get users on ingress gateway", "nodeid", ingressID, "network", node.Network, "user", r.Header.Get("user"), slog.Error(
"error", err) "failed to get users on ingress gateway",
"nodeid",
ingressID,
"network",
node.Network,
"user",
r.Header.Get("user"),
"error",
err,
)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }

3105
swagger.yaml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff