Only allow simple names when creating workers, VMs, etc. and escape paths in API client (#129)
* Controller: only allow simple names when creating workers, VMs, etc. * Client: escape paths * simplename: allow ':' character
This commit is contained in:
parent
2adb17c3c4
commit
8c62df0eba
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
storepkg "github.com/cirruslabs/orchard/internal/controller/store"
|
||||
"github.com/cirruslabs/orchard/internal/responder"
|
||||
"github.com/cirruslabs/orchard/internal/simplename"
|
||||
v1 "github.com/cirruslabs/orchard/pkg/resource/v1"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
|
|
@ -23,7 +24,11 @@ func (controller *Controller) createServiceAccount(ctx *gin.Context) responder.R
|
|||
}
|
||||
|
||||
if serviceAccount.Name == "" {
|
||||
return responder.JSON(http.StatusPreconditionFailed, NewErrorResponse("service account name is empty"))
|
||||
return responder.JSON(http.StatusPreconditionFailed,
|
||||
NewErrorResponse("service account name is empty"))
|
||||
} else if err := simplename.Validate(serviceAccount.Name); err != nil {
|
||||
return responder.JSON(http.StatusPreconditionFailed,
|
||||
NewErrorResponse("service account %v", err))
|
||||
}
|
||||
|
||||
// validate roles
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
storepkg "github.com/cirruslabs/orchard/internal/controller/store"
|
||||
"github.com/cirruslabs/orchard/internal/responder"
|
||||
"github.com/cirruslabs/orchard/internal/simplename"
|
||||
"github.com/cirruslabs/orchard/pkg/resource/v1"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
|
|
@ -25,6 +26,9 @@ func (controller *Controller) createVM(ctx *gin.Context) responder.Responder {
|
|||
|
||||
if vm.Name == "" {
|
||||
return responder.JSON(http.StatusPreconditionFailed, NewErrorResponse("VM name is empty"))
|
||||
} else if err := simplename.Validate(vm.Name); err != nil {
|
||||
return responder.JSON(http.StatusPreconditionFailed,
|
||||
NewErrorResponse("VM name %v", err))
|
||||
}
|
||||
if vm.Image == "" {
|
||||
return responder.JSON(http.StatusPreconditionFailed, NewErrorResponse("VM image is empty"))
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
storepkg "github.com/cirruslabs/orchard/internal/controller/store"
|
||||
"github.com/cirruslabs/orchard/internal/responder"
|
||||
"github.com/cirruslabs/orchard/internal/simplename"
|
||||
v1 "github.com/cirruslabs/orchard/pkg/resource/v1"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
|
|
@ -23,6 +24,9 @@ func (controller *Controller) createWorker(ctx *gin.Context) responder.Responder
|
|||
|
||||
if worker.Name == "" {
|
||||
return responder.JSON(http.StatusPreconditionFailed, NewErrorResponse("worker name is empty"))
|
||||
} else if err := simplename.Validate(worker.Name); err != nil {
|
||||
return responder.JSON(http.StatusPreconditionFailed,
|
||||
NewErrorResponse("worker name %v", err))
|
||||
}
|
||||
|
||||
currentTime := time.Now()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package simplename
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrNotASimpleName = errors.New("name contains restricted characters, please only use [A-Za-z0-9:-_.]")
|
||||
|
||||
func Validate(s string) error {
|
||||
for _, ch := range s {
|
||||
if ch >= 'a' && ch <= 'z' {
|
||||
continue
|
||||
}
|
||||
|
||||
if ch >= 'A' && ch <= 'Z' {
|
||||
continue
|
||||
}
|
||||
|
||||
if ch >= '0' && ch <= '9' {
|
||||
continue
|
||||
}
|
||||
|
||||
if ch == ':' || ch == '-' || ch == '_' || ch == '.' {
|
||||
continue
|
||||
}
|
||||
|
||||
return ErrNotASimpleName
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package simplename_test
|
||||
|
||||
import (
|
||||
"github.com/cirruslabs/orchard/internal/simplename"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
require.NoError(t, simplename.Validate("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz:-_."))
|
||||
require.NoError(t, simplename.Validate("vm-1"))
|
||||
require.NoError(t, simplename.Validate("vm_2"))
|
||||
require.NoError(t, simplename.Validate("host.local"))
|
||||
|
||||
require.Error(t, simplename.Validate("vm%"), "special characters")
|
||||
require.Error(t, simplename.Validate("😐"), "non-ASCII characters")
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/cirruslabs/orchard/pkg/resource/v1"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type ServiceAccountsService struct {
|
||||
|
|
@ -36,7 +37,8 @@ func (service *ServiceAccountsService) List(ctx context.Context) ([]v1.ServiceAc
|
|||
func (service *ServiceAccountsService) Get(ctx context.Context, name string) (*v1.ServiceAccount, error) {
|
||||
var serviceAccount v1.ServiceAccount
|
||||
|
||||
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("service-accounts/%s", name),
|
||||
err := service.client.request(ctx, http.MethodGet,
|
||||
fmt.Sprintf("service-accounts/%s", url.PathEscape(name)),
|
||||
nil, &serviceAccount, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -46,7 +48,8 @@ func (service *ServiceAccountsService) Get(ctx context.Context, name string) (*v
|
|||
}
|
||||
|
||||
func (service *ServiceAccountsService) Update(ctx context.Context, serviceAccount *v1.ServiceAccount) error {
|
||||
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("service-accounts/%s", serviceAccount.Name),
|
||||
err := service.client.request(ctx, http.MethodPut,
|
||||
fmt.Sprintf("service-accounts/%s", url.PathEscape(serviceAccount.Name)),
|
||||
serviceAccount, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -62,7 +65,8 @@ func (service *ServiceAccountsService) Delete(ctx context.Context, name string,
|
|||
params["force"] = "true"
|
||||
}
|
||||
|
||||
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("service-accounts/%s", name),
|
||||
err := service.client.request(ctx, http.MethodDelete,
|
||||
fmt.Sprintf("service-accounts/%s", url.PathEscape(name)),
|
||||
nil, nil, params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/cirruslabs/orchard/pkg/resource/v1"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ func (service *VMsService) List(ctx context.Context) ([]v1.VM, error) {
|
|||
func (service *VMsService) Get(ctx context.Context, name string) (*v1.VM, error) {
|
||||
var vm v1.VM
|
||||
|
||||
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("vms/%s", name),
|
||||
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("vms/%s", url.PathEscape(name)),
|
||||
nil, &vm, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -68,7 +69,7 @@ func (service *VMsService) Get(ctx context.Context, name string) (*v1.VM, error)
|
|||
|
||||
func (service *VMsService) Update(ctx context.Context, vm v1.VM) (*v1.VM, error) {
|
||||
var updatedVM v1.VM
|
||||
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("vms/%s", vm.Name),
|
||||
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("vms/%s", url.PathEscape(vm.Name)),
|
||||
vm, &updatedVM, nil)
|
||||
if err != nil {
|
||||
return &updatedVM, err
|
||||
|
|
@ -78,7 +79,7 @@ func (service *VMsService) Update(ctx context.Context, vm v1.VM) (*v1.VM, error)
|
|||
}
|
||||
|
||||
func (service *VMsService) Delete(ctx context.Context, name string) error {
|
||||
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("vms/%s", name),
|
||||
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("vms/%s", url.PathEscape(name)),
|
||||
nil, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -93,7 +94,7 @@ func (service *VMsService) PortForward(
|
|||
port uint16,
|
||||
waitSeconds uint16,
|
||||
) (net.Conn, error) {
|
||||
return service.client.wsRequest(ctx, fmt.Sprintf("vms/%s/port-forward", name),
|
||||
return service.client.wsRequest(ctx, fmt.Sprintf("vms/%s/port-forward", url.PathEscape(name)),
|
||||
map[string]string{
|
||||
"port": strconv.FormatUint(uint64(port), 10),
|
||||
"wait": strconv.FormatUint(uint64(waitSeconds), 10),
|
||||
|
|
@ -101,12 +102,12 @@ func (service *VMsService) PortForward(
|
|||
}
|
||||
|
||||
func (service *VMsService) StreamEvents(name string) *EventStreamer {
|
||||
return NewEventStreamer(service.client, fmt.Sprintf("vms/%s/events", name))
|
||||
return NewEventStreamer(service.client, fmt.Sprintf("vms/%s/events", url.PathEscape(name)))
|
||||
}
|
||||
|
||||
func (service *VMsService) Logs(ctx context.Context, name string) (lines []string, err error) {
|
||||
var events []v1.Event
|
||||
err = service.client.request(ctx, http.MethodGet, fmt.Sprintf("vms/%s/events", name),
|
||||
err = service.client.request(ctx, http.MethodGet, fmt.Sprintf("vms/%s/events", url.PathEscape(name)),
|
||||
nil, &events, nil)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/cirruslabs/orchard/pkg/resource/v1"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type WorkersService struct {
|
||||
|
|
@ -36,7 +37,7 @@ func (service *WorkersService) List(ctx context.Context) ([]v1.Worker, error) {
|
|||
func (service *WorkersService) Get(ctx context.Context, name string) (*v1.Worker, error) {
|
||||
var worker v1.Worker
|
||||
|
||||
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("workers/%s", name),
|
||||
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("workers/%s", url.PathEscape(name)),
|
||||
nil, &worker, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -46,7 +47,7 @@ func (service *WorkersService) Get(ctx context.Context, name string) (*v1.Worker
|
|||
}
|
||||
|
||||
func (service *WorkersService) Update(ctx context.Context, worker v1.Worker) (*v1.Worker, error) {
|
||||
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("workers/%s", worker.Name),
|
||||
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("workers/%s", url.PathEscape(worker.Name)),
|
||||
worker, &worker, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -56,7 +57,7 @@ func (service *WorkersService) Update(ctx context.Context, worker v1.Worker) (*v
|
|||
}
|
||||
|
||||
func (service *WorkersService) Delete(ctx context.Context, name string) error {
|
||||
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("workers/%s", name),
|
||||
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("workers/%s", url.PathEscape(name)),
|
||||
nil, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
Loading…
Reference in New Issue