From 58c38b78620f5b2012a14c99cbb1c371b4c0bfcb Mon Sep 17 00:00:00 2001 From: ecmadao Date: Tue, 11 Mar 2025 17:46:15 +0800 Subject: [PATCH] fix: escape params in the url --- client/auth.go | 4 ++-- client/common.go | 9 +++++---- client/group.go | 3 ++- provider/data_source_user.go | 5 +++++ provider/resource_user.go | 21 +++++++++++++++++++-- 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/client/auth.go b/client/auth.go index 173fb93..19109b9 100644 --- a/client/auth.go +++ b/client/auth.go @@ -14,7 +14,7 @@ import ( // Login will login the user and get the response. func (c *client) login(request *v1pb.LoginRequest) (*v1pb.LoginResponse, error) { if request.Email == "" || request.Password == "" { - return nil, errors.Errorf("define username and password") + return nil, errors.Errorf("undefined login service account or key") } rb, err := protojson.Marshal(request) if err != nil { @@ -28,7 +28,7 @@ func (c *client) login(request *v1pb.LoginRequest) (*v1pb.LoginResponse, error) body, err := c.doRequest(req) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "failed to login") } ar := v1pb.LoginResponse{} diff --git a/client/common.go b/client/common.go index 23447d1..32afcdc 100644 --- a/client/common.go +++ b/client/common.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "net/url" "strings" "google.golang.org/protobuf/encoding/protojson" @@ -15,7 +16,7 @@ var ProtojsonUnmarshaler = protojson.UnmarshalOptions{DiscardUnknown: true} // deleteResource deletes the resource by name. func (c *client) deleteResource(ctx context.Context, name string) error { - req, err := http.NewRequestWithContext(ctx, "DELETE", fmt.Sprintf("%s/%s/%s", c.url, c.version, name), nil) + req, err := http.NewRequestWithContext(ctx, "DELETE", fmt.Sprintf("%s/%s/%s", c.url, c.version, url.QueryEscape(name)), nil) if err != nil { return err } @@ -28,7 +29,7 @@ func (c *client) deleteResource(ctx context.Context, name string) error { // undeleteResource undeletes the resource by name. func (c *client) undeleteResource(ctx context.Context, name string) ([]byte, error) { - req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/%s/%s:undelete", c.url, c.version, name), nil) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/%s/%s:undelete", c.url, c.version, url.QueryEscape(name)), nil) if err != nil { return nil, err } @@ -48,7 +49,7 @@ func (c *client) updateResource(ctx context.Context, name string, patch protoref return nil, err } - req, err := http.NewRequestWithContext(ctx, "PATCH", fmt.Sprintf("%s/%s/%s?update_mask=%s&allow_missing=%v", c.url, c.version, name, strings.Join(updateMasks, ","), allowMissing), strings.NewReader(string(payload))) + req, err := http.NewRequestWithContext(ctx, "PATCH", fmt.Sprintf("%s/%s/%s?update_mask=%s&allow_missing=%v", c.url, c.version, url.QueryEscape(name), strings.Join(updateMasks, ","), allowMissing), strings.NewReader(string(payload))) if err != nil { return nil, err } @@ -63,7 +64,7 @@ func (c *client) updateResource(ctx context.Context, name string, patch protoref // getResource gets the resource by name. func (c *client) getResource(ctx context.Context, name string) ([]byte, error) { - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s/%s", c.url, c.version, name), nil) + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s/%s", c.url, c.version, url.QueryEscape(name)), nil) if err != nil { return nil, err } diff --git a/client/group.go b/client/group.go index 2c63172..601ba24 100644 --- a/client/group.go +++ b/client/group.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "net/url" "strings" v1pb "github.com/bytebase/bytebase/proto/generated-go/v1" @@ -37,7 +38,7 @@ func (c *client) CreateGroup(ctx context.Context, email string, group *v1pb.Grou return nil, err } - req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/%s/groups?groupEmail=%s", c.url, c.version, email), strings.NewReader(string(payload))) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/%s/groups?groupEmail=%s", c.url, c.version, url.QueryEscape(email)), strings.NewReader(string(payload))) if err != nil { return nil, err diff --git a/provider/data_source_user.go b/provider/data_source_user.go index 6f6f380..8553765 100644 --- a/provider/data_source_user.go +++ b/provider/data_source_user.go @@ -131,6 +131,11 @@ func setUser(ctx context.Context, client api.Client, d *schema.ResourceData, use if err := d.Set("type", user.UserType.String()); err != nil { return diag.Errorf("cannot set type for user: %s", err.Error()) } + if user.ServiceKey != "" { + if err := d.Set("service_key", user.ServiceKey); err != nil { + return diag.Errorf("cannot set the service_key: %s", err.Error()) + } + } if err := d.Set("mfa_enabled", user.MfaEnabled); err != nil { return diag.Errorf("cannot set mfa_enabled for user: %s", err.Error()) } diff --git a/provider/resource_user.go b/provider/resource_user.go index 4580b52..66b9002 100644 --- a/provider/resource_user.go +++ b/provider/resource_user.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "slices" + "strings" v1pb "github.com/bytebase/bytebase/proto/generated-go/v1" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -51,6 +52,11 @@ func resourceUser() *schema.Resource { Optional: true, Description: "The user login password.", }, + "service_key": { + Type: schema.TypeString, + Computed: true, + Description: "The service key for service account.", + }, "roles": { Type: schema.TypeSet, Optional: true, @@ -61,8 +67,13 @@ func resourceUser() *schema.Resource { }, "type": { Type: schema.TypeString, - Computed: true, + Optional: true, Description: "The user type.", + Default: v1pb.UserType_USER.String(), + ValidateFunc: validation.StringInSlice([]string{ + v1pb.UserType_SERVICE_ACCOUNT.String(), + v1pb.UserType_USER.String(), + }, false), }, "name": { Type: schema.TypeString, @@ -198,13 +209,19 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, m interface } d.SetId(existedUser.Name) } else { + userType := v1pb.UserType(v1pb.UserType_value[d.Get("type").(string)]) + if userType == v1pb.UserType_SERVICE_ACCOUNT { + if !strings.HasSuffix(email, "@service.bytebase.com") { + return diag.Errorf(`service account email must ends with "@service.bytebase.com"`) + } + } user, err := c.CreateUser(ctx, &v1pb.User{ Name: userName, Title: title, Password: password, Phone: phone, Email: email, - UserType: v1pb.UserType_USER, + UserType: userType, State: v1pb.State_ACTIVE, }) if err != nil {