Path: blob/main/components/public-api-server/pkg/apiv1/validation.go
2499 views
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package apiv156import (7"context"8"errors"9"fmt"10"strings"1112connect "github.com/bufbuild/connect-go"13"github.com/gitpod-io/gitpod/common-go/log"14"github.com/gitpod-io/gitpod/common-go/namegen"15"github.com/google/uuid"16"github.com/relvacode/iso8601"17"google.golang.org/protobuf/proto"18"google.golang.org/protobuf/types/known/fieldmaskpb"19"google.golang.org/protobuf/types/known/timestamppb"20)2122func validateTeamID(ctx context.Context, id string) (uuid.UUID, error) {23log.AddFields(ctx, log.OrganizationID(id))24teamID, err := validateUUID(id)25if err != nil {26return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Team ID must be a valid UUID."))27}2829return teamID, nil30}3132func parseGitpodTimeStampOrDefault(s string) *timestamppb.Timestamp {33parsed, err := parseGitpodTimestamp(s)34if err != nil {35return ×tamppb.Timestamp{}36}37return parsed38}3940func parseGitpodTimestamp(input string) (*timestamppb.Timestamp, error) {41parsed, err := iso8601.ParseString(input)42if err != nil {43return nil, err44}45return timestamppb.New(parsed), nil46}4748func validateWorkspaceID(ctx context.Context, id string) (string, error) {49log.AddFields(ctx, log.WorkspaceID(id))50if id == "" {51return "", connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Empty workspace id specified"))52}5354err := namegen.ValidateWorkspaceID(id)55if err != nil {56return "", connect.NewError(connect.CodeInvalidArgument, err)57}5859return id, nil60}6162func validateProjectID(ctx context.Context, id string) (uuid.UUID, error) {63log.AddFields(ctx, log.ProjectID(id))64projectID, err := validateUUID(id)65if err != nil {66return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Project ID must be a valid UUID."))67}6869return projectID, nil70}7172func validatePersonalAccessTokenID(ctx context.Context, id string) (uuid.UUID, error) {73log.AddFields(ctx, log.PersonalAccessTokenID(id))74tokenID, err := validateUUID(id)75if err != nil {76return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Token ID must be a valid UUID"))77}7879return tokenID, nil80}8182func validateOrganizationID(ctx context.Context, id string) (uuid.UUID, error) {83log.AddFields(ctx, log.OrganizationID(id))84organizationID, err := validateUUID(id)85if err != nil {86return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("OrganizationID must be a valid UUID"))87}8889return organizationID, nil90}9192func validateOIDCClientConfigID(ctx context.Context, id string) (uuid.UUID, error) {93log.AddFields(ctx, log.OIDCClientConfigID(id))94oidcClientConfigID, err := validateUUID(id)95if err != nil {96return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("OIDC Client Config ID must be a valid UUID"))97}9899return oidcClientConfigID, nil100}101102func validateFieldMask(mask *fieldmaskpb.FieldMask, message proto.Message) (*fieldmaskpb.FieldMask, error) {103if mask == nil {104return &fieldmaskpb.FieldMask{}, nil105}106107mask.Normalize()108if !mask.IsValid(message) {109return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("Invalid field mask specified."))110}111112return mask, nil113}114115func validateUUID(id string) (uuid.UUID, error) {116trimmed := strings.TrimSpace(id)117if trimmed == "" {118return uuid.Nil, errors.New("empty uuid")119}120121return uuid.Parse(trimmed)122}123124125