diff --git a/README.md b/README.md index 1d480cd..3605625 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ This project acts as a client SDK implementation written in Go to interact with the Gitea API implementation. For further informations take a look at the current [documentation](https://godoc.org/code.gitea.io/sdk/gitea). +Note: function arguments are escaped by the SDK. + ## Use it ```go diff --git a/docs/migrate-v0.13-to-v0.14.md b/docs/migrate-v0.13-to-v0.14.md index 734b45c..1c03f94 100644 --- a/docs/migrate-v0.13-to-v0.14.md +++ b/docs/migrate-v0.13-to-v0.14.md @@ -9,6 +9,7 @@ feel free to create an issue. - [Removed Functions (#467)](#removed-functions) - [Renamed Functions (#467)](#renamed-functions) - [New Optional Fields (#486)](#new-optional-fields) +- [Arguemnts are escapted by the SDK iteslve now (#273)](#escape-function-arguments) @@ -38,3 +39,9 @@ The easiest migration path is, to wrap your options with: Pulls: - [#486 Update Structs](https://gitea.com/gitea/go-sdk/pulls/486) + + +## Escape Function Arguments + +String arguments like `user`, `repo`, `tag`, ... are now url/path/query escapted as they need. +If you had issues and did escape arguments by yourselve you have to remove this now. diff --git a/gitea/admin_cron.go b/gitea/admin_cron.go index 99006b6..84316da 100644 --- a/gitea/admin_cron.go +++ b/gitea/admin_cron.go @@ -39,6 +39,9 @@ func (c *Client) RunCronTasks(task string) (*Response, error) { if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, err } + if err := escapeValidatePathSegments(&task); err != nil { + return nil, err + } _, resp, err := c.getResponse("POST", fmt.Sprintf("/admin/cron/%s", task), jsonHeader, nil) return resp, err } diff --git a/gitea/admin_org.go b/gitea/admin_org.go index e572680..26bf81f 100644 --- a/gitea/admin_org.go +++ b/gitea/admin_org.go @@ -26,6 +26,9 @@ func (c *Client) AdminListOrgs(opt AdminListOrgsOptions) ([]*Organization, *Resp // AdminCreateOrg create an organization func (c *Client) AdminCreateOrg(user string, opt CreateOrgOption) (*Organization, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err diff --git a/gitea/admin_repo.go b/gitea/admin_repo.go index cbd9788..8666690 100644 --- a/gitea/admin_repo.go +++ b/gitea/admin_repo.go @@ -12,6 +12,9 @@ import ( // AdminCreateRepo create a repo func (c *Client) AdminCreateRepo(user string, opt CreateRepoOption) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err diff --git a/gitea/admin_user.go b/gitea/admin_user.go index a24f260..161dc60 100644 --- a/gitea/admin_user.go +++ b/gitea/admin_user.go @@ -82,6 +82,9 @@ type EditUserOption struct { // AdminEditUser modify user informations func (c *Client) AdminEditUser(user string, opt EditUserOption) (*Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, err @@ -92,12 +95,18 @@ func (c *Client) AdminEditUser(user string, opt EditUserOption) (*Response, erro // AdminDeleteUser delete one user according name func (c *Client) AdminDeleteUser(user string) (*Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s", user), nil, nil) return resp, err } // AdminCreateUserPublicKey adds a public key for the user func (c *Client) AdminCreateUserPublicKey(user string, opt CreateKeyOption) (*PublicKey, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -109,6 +118,9 @@ func (c *Client) AdminCreateUserPublicKey(user string, opt CreateKeyOption) (*Pu // AdminDeleteUserPublicKey deletes a user's public key func (c *Client) AdminDeleteUserPublicKey(user string, keyID int) (*Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s/keys/%d", user, keyID), nil, nil) return resp, err } diff --git a/gitea/attachment.go b/gitea/attachment.go index 6f67ae3..24c57ba 100644 --- a/gitea/attachment.go +++ b/gitea/attachment.go @@ -31,6 +31,9 @@ type ListReleaseAttachmentsOptions struct { // ListReleaseAttachments list release's attachments func (c *Client) ListReleaseAttachments(user, repo string, release int64, opt ListReleaseAttachmentsOptions) ([]*Attachment, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() attachments := make([]*Attachment, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", @@ -41,6 +44,9 @@ func (c *Client) ListReleaseAttachments(user, repo string, release int64, opt Li // GetReleaseAttachment returns the requested attachment func (c *Client) GetReleaseAttachment(user, repo string, release int64, id int64) (*Attachment, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } a := new(Attachment) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id), @@ -50,6 +56,9 @@ func (c *Client) GetReleaseAttachment(user, repo string, release int64, id int64 // CreateReleaseAttachment creates an attachment for the given release func (c *Client) CreateReleaseAttachment(user, repo string, release int64, file io.Reader, filename string) (*Attachment, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } // Write file to body body := new(bytes.Buffer) writer := multipart.NewWriter(body) @@ -80,6 +89,9 @@ type EditAttachmentOptions struct { // EditReleaseAttachment updates the given attachment with the given options func (c *Client) EditReleaseAttachment(user, repo string, release int64, attachment int64, form EditAttachmentOptions) (*Attachment, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(&form) if err != nil { return nil, nil, err @@ -91,6 +103,9 @@ func (c *Client) EditReleaseAttachment(user, repo string, release int64, attachm // DeleteReleaseAttachment deletes the given attachment including the uploaded file func (c *Client) DeleteReleaseAttachment(user, repo string, release int64, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id), nil, nil) return resp, err } diff --git a/gitea/client.go b/gitea/client.go index 1b22711..9f857f8 100644 --- a/gitea/client.go +++ b/gitea/client.go @@ -13,6 +13,7 @@ import ( "io" "io/ioutil" "net/http" + "net/url" "strings" "sync" @@ -309,3 +310,24 @@ func (c *Client) getStatusCode(method, path string, header http.Header, body io. return resp.StatusCode, resp, nil } + +// pathEscapeSegments escapes segments of a path while not escaping forward slash +func pathEscapeSegments(path string) string { + slice := strings.Split(path, "/") + for index := range slice { + slice[index] = url.PathEscape(slice[index]) + } + escapedPath := strings.Join(slice, "/") + return escapedPath +} + +// escapeValidatePathSegments is a help function to validate and encode url path segments +func escapeValidatePathSegments(seg ...*string) error { + for i := range seg { + if seg[i] == nil || len(*seg[i]) == 0 { + return fmt.Errorf("path segment [%d] is empty", i) + } + *seg[i] = url.PathEscape(*seg[i]) + } + return nil +} diff --git a/gitea/fork.go b/gitea/fork.go index a519712..c8e5323 100644 --- a/gitea/fork.go +++ b/gitea/fork.go @@ -17,6 +17,9 @@ type ListForksOptions struct { // ListForks list a repository's forks func (c *Client) ListForks(user string, repo string, opt ListForksOptions) ([]*Repository, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() forks := make([]*Repository, opt.PageSize) resp, err := c.getParsedResponse("GET", @@ -33,6 +36,9 @@ type CreateForkOption struct { // CreateFork create a fork of a repository func (c *Client) CreateFork(user, repo string, form CreateForkOption) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(form) if err != nil { return nil, nil, err diff --git a/gitea/git_blob.go b/gitea/git_blob.go index 262fd92..7668672 100644 --- a/gitea/git_blob.go +++ b/gitea/git_blob.go @@ -19,6 +19,9 @@ type GitBlobResponse struct { // GetBlob get the blob of a repository file func (c *Client) GetBlob(user, repo, sha string) (*GitBlobResponse, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &sha); err != nil { + return nil, nil, err + } blob := new(GitBlobResponse) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/blobs/%s", user, repo, sha), nil, nil, blob) return blob, resp, err diff --git a/gitea/git_hook.go b/gitea/git_hook.go index 520ce53..d8fbf71 100644 --- a/gitea/git_hook.go +++ b/gitea/git_hook.go @@ -24,6 +24,9 @@ type ListRepoGitHooksOptions struct { // ListRepoGitHooks list all the Git hooks of one repository func (c *Client) ListRepoGitHooks(user, repo string, opt ListRepoGitHooksOptions) ([]*GitHook, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() hooks := make([]*GitHook, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/git?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &hooks) @@ -32,6 +35,9 @@ func (c *Client) ListRepoGitHooks(user, repo string, opt ListRepoGitHooksOptions // GetRepoGitHook get a Git hook of a repository func (c *Client) GetRepoGitHook(user, repo, id string) (*GitHook, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &id); err != nil { + return nil, nil, err + } h := new(GitHook) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), nil, nil, h) return h, resp, err @@ -44,6 +50,9 @@ type EditGitHookOption struct { // EditRepoGitHook modify one Git hook of a repository func (c *Client) EditRepoGitHook(user, repo, id string, opt EditGitHookOption) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &id); err != nil { + return nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, err @@ -54,6 +63,9 @@ func (c *Client) EditRepoGitHook(user, repo, id string, opt EditGitHookOption) ( // DeleteRepoGitHook delete one Git hook from a repository func (c *Client) DeleteRepoGitHook(user, repo, id string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &id); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), nil, nil) return resp, err } diff --git a/gitea/hook.go b/gitea/hook.go index 3a6be65..af4154e 100644 --- a/gitea/hook.go +++ b/gitea/hook.go @@ -31,6 +31,9 @@ type ListHooksOptions struct { // ListOrgHooks list all the hooks of one organization func (c *Client) ListOrgHooks(org string, opt ListHooksOptions) ([]*Hook, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } opt.setDefaults() hooks := make([]*Hook, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks?%s", org, opt.getURLQuery().Encode()), nil, nil, &hooks) @@ -39,6 +42,9 @@ func (c *Client) ListOrgHooks(org string, opt ListHooksOptions) ([]*Hook, *Respo // ListRepoHooks list all the hooks of one repository func (c *Client) ListRepoHooks(user, repo string, opt ListHooksOptions) ([]*Hook, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() hooks := make([]*Hook, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &hooks) @@ -47,6 +53,9 @@ func (c *Client) ListRepoHooks(user, repo string, opt ListHooksOptions) ([]*Hook // GetOrgHook get a hook of an organization func (c *Client) GetOrgHook(org string, id int64) (*Hook, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } h := new(Hook) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), nil, nil, h) return h, resp, err @@ -54,6 +63,9 @@ func (c *Client) GetOrgHook(org string, id int64) (*Hook, *Response, error) { // GetRepoHook get a hook of a repository func (c *Client) GetRepoHook(user, repo string, id int64) (*Hook, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } h := new(Hook) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil, h) return h, resp, err @@ -78,6 +90,9 @@ func (opt CreateHookOption) Validate() error { // CreateOrgHook create one hook for an organization, with options func (c *Client) CreateOrgHook(org string, opt CreateHookOption) (*Hook, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -92,6 +107,9 @@ func (c *Client) CreateOrgHook(org string, opt CreateHookOption) (*Hook, *Respon // CreateRepoHook create one hook for a repository, with options func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -111,6 +129,9 @@ type EditHookOption struct { // EditOrgHook modify one hook of an organization, with hook id and options func (c *Client) EditOrgHook(org string, id int64, opt EditHookOption) (*Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, err @@ -121,6 +142,9 @@ func (c *Client) EditOrgHook(org string, id int64, opt EditHookOption) (*Respons // EditRepoHook modify one hook of a repository, with hook id and options func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, err @@ -131,12 +155,18 @@ func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) ( // DeleteOrgHook delete one hook from an organization, with hook id func (c *Client) DeleteOrgHook(org string, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), nil, nil) return resp, err } // DeleteRepoHook delete one hook from a repository, with hook id func (c *Client) DeleteRepoHook(user, repo string, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil) return resp, err } diff --git a/gitea/issue.go b/gitea/issue.go index 211cb24..6889246 100644 --- a/gitea/issue.go +++ b/gitea/issue.go @@ -140,6 +140,9 @@ func (c *Client) ListIssues(opt ListIssueOption) ([]*Issue, *Response, error) { // ListRepoIssues returns all issues for a given repository func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Issue, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() issues := make([]*Issue, 0, opt.PageSize) @@ -161,6 +164,9 @@ func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Iss // GetIssue returns a single issue for a given repository func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } issue := new(Issue) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), nil, nil, issue) if e := c.checkServerVersionGreaterThanOrEqual(version1_12_0); e != nil && issue.Repository != nil { @@ -197,6 +203,9 @@ func (opt CreateIssueOption) Validate() error { // CreateIssue create a new issue for a given repository func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -236,6 +245,9 @@ func (opt EditIssueOption) Validate() error { // EditIssue modify an existing issue for a given repository func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption) (*Issue, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } diff --git a/gitea/issue_comment.go b/gitea/issue_comment.go index 4eff850..8131a6e 100644 --- a/gitea/issue_comment.go +++ b/gitea/issue_comment.go @@ -47,6 +47,9 @@ func (opt *ListIssueCommentOptions) QueryEncode() string { // ListIssueComments list comments on an issue. func (c *Client) ListIssueComments(owner, repo string, index int64, opt ListIssueCommentOptions) ([]*Comment, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index)) link.RawQuery = opt.QueryEncode() @@ -57,6 +60,9 @@ func (c *Client) ListIssueComments(owner, repo string, index int64, opt ListIssu // ListRepoIssueComments list comments for a given repo. func (c *Client) ListRepoIssueComments(owner, repo string, opt ListIssueCommentOptions) ([]*Comment, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues/comments", owner, repo)) link.RawQuery = opt.QueryEncode() @@ -67,6 +73,9 @@ func (c *Client) ListRepoIssueComments(owner, repo string, opt ListIssueCommentO // GetIssueComment get a comment for a given repo by id. func (c *Client) GetIssueComment(owner, repo string, id int64) (*Comment, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } comment := new(Comment) if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return comment, nil, err @@ -90,6 +99,9 @@ func (opt CreateIssueCommentOption) Validate() error { // CreateIssueComment create comment on an issue. func (c *Client) CreateIssueComment(owner, repo string, index int64, opt CreateIssueCommentOption) (*Comment, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -117,6 +129,9 @@ func (opt EditIssueCommentOption) Validate() error { // EditIssueComment edits an issue comment. func (c *Client) EditIssueComment(owner, repo string, commentID int64, opt EditIssueCommentOption) (*Comment, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -131,6 +146,9 @@ func (c *Client) EditIssueComment(owner, repo string, commentID int64, opt EditI // DeleteIssueComment deletes an issue comment. func (c *Client) DeleteIssueComment(owner, repo string, commentID int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, commentID), nil, nil) return resp, err } diff --git a/gitea/issue_label.go b/gitea/issue_label.go index b664dac..f343ee5 100644 --- a/gitea/issue_label.go +++ b/gitea/issue_label.go @@ -29,6 +29,9 @@ type ListLabelsOptions struct { // ListRepoLabels list labels of one repository func (c *Client) ListRepoLabels(owner, repo string, opt ListLabelsOptions) ([]*Label, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() labels := make([]*Label, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels?%s", owner, repo, opt.getURLQuery().Encode()), nil, nil, &labels) @@ -37,6 +40,9 @@ func (c *Client) ListRepoLabels(owner, repo string, opt ListLabelsOptions) ([]*L // GetRepoLabel get one label of repository by repo it func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } label := new(Label) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil, label) return label, resp, err @@ -67,6 +73,9 @@ func (opt CreateLabelOption) Validate() error { // CreateLabel create one label of repository func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -114,6 +123,9 @@ func (opt EditLabelOption) Validate() error { // EditLabel modify one label with options func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (*Label, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -128,12 +140,18 @@ func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (* // DeleteLabel delete one label of repository by id func (c *Client) DeleteLabel(owner, repo string, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil) return resp, err } // GetIssueLabels get labels of one issue via issue id func (c *Client) GetIssueLabels(owner, repo string, index int64, opts ListLabelsOptions) ([]*Label, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } labels := make([]*Label, 0, 5) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/labels?%s", owner, repo, index, opts.getURLQuery().Encode()), nil, nil, &labels) return labels, resp, err @@ -147,6 +165,9 @@ type IssueLabelsOption struct { // AddIssueLabels add one or more labels to one issue func (c *Client) AddIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -158,6 +179,9 @@ func (c *Client) AddIssueLabels(owner, repo string, index int64, opt IssueLabels // ReplaceIssueLabels replace old labels of issue with new labels func (c *Client) ReplaceIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -170,12 +194,18 @@ func (c *Client) ReplaceIssueLabels(owner, repo string, index int64, opt IssueLa // DeleteIssueLabel delete one label of one issue by issue id and label id // TODO: maybe we need delete by label name and issue id func (c *Client) DeleteIssueLabel(owner, repo string, index, label int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels/%d", owner, repo, index, label), nil, nil) return resp, err } // ClearIssueLabels delete all the labels of one issue. func (c *Client) ClearIssueLabels(owner, repo string, index int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), nil, nil) return resp, err } diff --git a/gitea/issue_milestone.go b/gitea/issue_milestone.go index 236c236..a865a45 100644 --- a/gitea/issue_milestone.go +++ b/gitea/issue_milestone.go @@ -49,6 +49,9 @@ func (opt *ListMilestoneOption) QueryEncode() string { // ListRepoMilestones list all the milestones of one repository func (c *Client) ListRepoMilestones(owner, repo string, opt ListMilestoneOption) ([]*Milestone, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() milestones := make([]*Milestone, 0, opt.PageSize) @@ -60,6 +63,9 @@ func (c *Client) ListRepoMilestones(owner, repo string, opt ListMilestoneOption) // GetMilestone get one milestone by repo name and milestone id func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } milestone := new(Milestone) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil, milestone) return milestone, resp, err @@ -72,6 +78,9 @@ func (c *Client) GetMilestoneByName(owner, repo string, name string) (*Milestone m, resp, err := c.resolveMilestoneByName(owner, repo, name) return m, resp, err } + if err := escapeValidatePathSegments(&owner, &repo, &name); err != nil { + return nil, nil, err + } milestone := new(Milestone) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones/%s", owner, repo, name), nil, nil, milestone) return milestone, resp, err @@ -95,6 +104,9 @@ func (opt CreateMilestoneOption) Validate() error { // CreateMilestone create one milestone with options func (c *Client) CreateMilestone(owner, repo string, opt CreateMilestoneOption) (*Milestone, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -135,6 +147,9 @@ func (opt EditMilestoneOption) Validate() error { // EditMilestone modify milestone with options func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOption) (*Milestone, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -157,6 +172,9 @@ func (c *Client) EditMilestoneByName(owner, repo string, name string, opt EditMi } return c.EditMilestone(owner, repo, m.ID, opt) } + if err := escapeValidatePathSegments(&owner, &repo, &name); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -171,6 +189,9 @@ func (c *Client) EditMilestoneByName(owner, repo string, name string, opt EditMi // DeleteMilestone delete one milestone by id func (c *Client) DeleteMilestone(owner, repo string, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil) return resp, err } @@ -185,6 +206,9 @@ func (c *Client) DeleteMilestoneByName(owner, repo string, name string) (*Respon } return c.DeleteMilestone(owner, repo, m.ID) } + if err := escapeValidatePathSegments(&owner, &repo, &name); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/milestones/%s", owner, repo, name), nil, nil) return resp, err } diff --git a/gitea/issue_reaction.go b/gitea/issue_reaction.go index efdac08..b45c066 100644 --- a/gitea/issue_reaction.go +++ b/gitea/issue_reaction.go @@ -20,6 +20,9 @@ type Reaction struct { // GetIssueReactions get a list reactions of an issue func (c *Client) GetIssueReactions(owner, repo string, index int64) ([]*Reaction, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } reactions := make([]*Reaction, 0, 10) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index), nil, nil, &reactions) return reactions, resp, err @@ -27,6 +30,9 @@ func (c *Client) GetIssueReactions(owner, repo string, index int64) ([]*Reaction // GetIssueCommentReactions get a list of reactions from a comment of an issue func (c *Client) GetIssueCommentReactions(owner, repo string, commentID int64) ([]*Reaction, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } reactions := make([]*Reaction, 0, 10) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID), nil, nil, &reactions) return reactions, resp, err @@ -39,6 +45,9 @@ type editReactionOption struct { // PostIssueReaction add a reaction to an issue func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction string) (*Reaction, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } reactionResponse := new(Reaction) body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { @@ -52,6 +61,9 @@ func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction str // DeleteIssueReaction remove a reaction from an issue func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { return nil, err @@ -62,6 +74,9 @@ func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction s // PostIssueCommentReaction add a reaction to a comment of an issue func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Reaction, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } reactionResponse := new(Reaction) body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { @@ -75,6 +90,9 @@ func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, r // DeleteIssueCommentReaction remove a reaction from a comment of an issue func (c *Client) DeleteIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { return nil, err diff --git a/gitea/issue_stopwatch.go b/gitea/issue_stopwatch.go index 35e1efe..ebb0b8a 100644 --- a/gitea/issue_stopwatch.go +++ b/gitea/issue_stopwatch.go @@ -29,6 +29,9 @@ func (c *Client) GetMyStopwatches() ([]*StopWatch, *Response, error) { // DeleteIssueStopwatch delete / cancel a specific stopwatch func (c *Client) DeleteIssueStopwatch(owner, repo string, index int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/delete", owner, repo, index), nil, nil) return resp, err } @@ -36,6 +39,9 @@ func (c *Client) DeleteIssueStopwatch(owner, repo string, index int64) (*Respons // StartIssueStopWatch starts a stopwatch for an existing issue for a given // repository func (c *Client) StartIssueStopWatch(owner, repo string, index int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/start", owner, repo, index), nil, nil) return resp, err } @@ -43,6 +49,9 @@ func (c *Client) StartIssueStopWatch(owner, repo string, index int64) (*Response // StopIssueStopWatch stops an existing stopwatch for an issue in a given // repository func (c *Client) StopIssueStopWatch(owner, repo string, index int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/stop", owner, repo, index), nil, nil) return resp, err } diff --git a/gitea/issue_subscription.go b/gitea/issue_subscription.go index 35972ba..86853c7 100644 --- a/gitea/issue_subscription.go +++ b/gitea/issue_subscription.go @@ -11,6 +11,9 @@ import ( // GetIssueSubscribers get list of users who subscribed on an issue func (c *Client) GetIssueSubscribers(owner, repo string, index int64) ([]*User, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } subscribers := make([]*User, 0, 10) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions", owner, repo, index), nil, nil, &subscribers) return subscribers, resp, err @@ -18,6 +21,9 @@ func (c *Client) GetIssueSubscribers(owner, repo string, index int64) ([]*User, // AddIssueSubscription Subscribe user to issue func (c *Client) AddIssueSubscription(owner, repo string, index int64, user string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &user); err != nil { + return nil, err + } status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) if err != nil { return resp, err @@ -33,6 +39,9 @@ func (c *Client) AddIssueSubscription(owner, repo string, index int64, user stri // DeleteIssueSubscription unsubscribe user from issue func (c *Client) DeleteIssueSubscription(owner, repo string, index int64, user string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &user); err != nil { + return nil, err + } status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) if err != nil { return resp, err @@ -48,6 +57,9 @@ func (c *Client) DeleteIssueSubscription(owner, repo string, index int64, user s // CheckIssueSubscription check if current user is subscribed to an issue func (c *Client) CheckIssueSubscription(owner, repo string, index int64) (*WatchInfo, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } diff --git a/gitea/issue_tracked_time.go b/gitea/issue_tracked_time.go index 6a326cf..c558516 100644 --- a/gitea/issue_tracked_time.go +++ b/gitea/issue_tracked_time.go @@ -55,6 +55,9 @@ func (opt *ListTrackedTimesOptions) QueryEncode() string { // ListRepoTrackedTimes list tracked times of a repository func (c *Client) ListRepoTrackedTimes(owner, repo string, opt ListTrackedTimesOptions) ([]*TrackedTime, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/times", owner, repo)) opt.setDefaults() link.RawQuery = opt.QueryEncode() @@ -90,6 +93,9 @@ func (opt AddTimeOption) Validate() error { // AddTime adds time to issue with the given index func (c *Client) AddTime(owner, repo string, index int64, opt AddTimeOption) (*TrackedTime, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -106,6 +112,9 @@ func (c *Client) AddTime(owner, repo string, index int64, opt AddTimeOption) (*T // ListIssueTrackedTimes list tracked times of a single issue for a given repository func (c *Client) ListIssueTrackedTimes(owner, repo string, index int64, opt ListTrackedTimesOptions) ([]*TrackedTime, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues/%d/times", owner, repo, index)) opt.setDefaults() link.RawQuery = opt.QueryEncode() @@ -116,12 +125,18 @@ func (c *Client) ListIssueTrackedTimes(owner, repo string, index int64, opt List // ResetIssueTime reset tracked time of a single issue for a given repository func (c *Client) ResetIssueTime(owner, repo string, index int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times", owner, repo, index), jsonHeader, nil) return resp, err } // DeleteTime delete a specific tracked time by id of a single issue for a given repository func (c *Client) DeleteTime(owner, repo string, index, timeID int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times/%d", owner, repo, index, timeID), jsonHeader, nil) return resp, err } diff --git a/gitea/notifications.go b/gitea/notifications.go index 30b6b6d..de53e2c 100644 --- a/gitea/notifications.go +++ b/gitea/notifications.go @@ -176,14 +176,17 @@ func (c *Client) ReadNotifications(opt MarkNotificationOptions) (*Response, erro } // ListRepoNotifications list users's notification threads on a specific repo -func (c *Client) ListRepoNotifications(owner, reponame string, opt ListNotificationOptions) ([]*NotificationThread, *Response, error) { +func (c *Client) ListRepoNotifications(owner, repo string, opt ListNotificationOptions) ([]*NotificationThread, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } if err := opt.Validate(c); err != nil { return nil, nil, err } - link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, reponame)) + link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, repo)) link.RawQuery = opt.QueryEncode() threads := make([]*NotificationThread, 0, 10) resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &threads) @@ -191,14 +194,17 @@ func (c *Client) ListRepoNotifications(owner, reponame string, opt ListNotificat } // ReadRepoNotifications mark notification threads as read on a specific repo -func (c *Client) ReadRepoNotifications(owner, reponame string, opt MarkNotificationOptions) (*Response, error) { +func (c *Client) ReadRepoNotifications(owner, repo string, opt MarkNotificationOptions) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } if err := opt.Validate(c); err != nil { return nil, err } - link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, reponame)) + link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, repo)) link.RawQuery = opt.QueryEncode() _, resp, err := c.getResponse("PUT", link.String(), nil, nil) return resp, err diff --git a/gitea/org.go b/gitea/org.go index ed6c678..b7c439b 100644 --- a/gitea/org.go +++ b/gitea/org.go @@ -52,6 +52,9 @@ func (c *Client) ListMyOrgs(opt ListOrgsOptions) ([]*Organization, *Response, er // ListUserOrgs list all of some user's organizations func (c *Client) ListUserOrgs(user string, opt ListOrgsOptions) ([]*Organization, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } opt.setDefaults() orgs := make([]*Organization, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/orgs?%s", user, opt.getURLQuery().Encode()), nil, nil, &orgs) @@ -60,6 +63,9 @@ func (c *Client) ListUserOrgs(user string, opt ListOrgsOptions) ([]*Organization // GetOrg get one organization by name func (c *Client) GetOrg(orgname string) (*Organization, *Response, error) { + if err := escapeValidatePathSegments(&orgname); err != nil { + return nil, nil, err + } org := new(Organization) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s", orgname), nil, nil, org) return org, resp, err @@ -124,6 +130,9 @@ func (opt EditOrgOption) Validate() error { // EditOrg modify one organization via options func (c *Client) EditOrg(orgname string, opt EditOrgOption) (*Response, error) { + if err := escapeValidatePathSegments(&orgname); err != nil { + return nil, err + } if err := opt.Validate(); err != nil { return nil, err } @@ -137,6 +146,9 @@ func (c *Client) EditOrg(orgname string, opt EditOrgOption) (*Response, error) { // DeleteOrg deletes an organization func (c *Client) DeleteOrg(orgname string) (*Response, error) { + if err := escapeValidatePathSegments(&orgname); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s", orgname), jsonHeader, nil) return resp, err } diff --git a/gitea/org_member.go b/gitea/org_member.go index 0f5b542..1eed90f 100644 --- a/gitea/org_member.go +++ b/gitea/org_member.go @@ -12,7 +12,10 @@ import ( // DeleteOrgMembership remove a member from an organization func (c *Client) DeleteOrgMembership(org, user string) (*Response, error) { - _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) + if err := escapeValidatePathSegments(&org, &user); err != nil { + return nil, err + } + _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/members/%s", org, user), nil, nil) return resp, err } @@ -23,10 +26,13 @@ type ListOrgMembershipOption struct { // ListOrgMembership list an organization's members func (c *Client) ListOrgMembership(org string, opt ListOrgMembershipOption) ([]*User, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } opt.setDefaults() users := make([]*User, 0, opt.PageSize) - link, _ := url.Parse(fmt.Sprintf("/orgs/%s/members", url.PathEscape(org))) + link, _ := url.Parse(fmt.Sprintf("/orgs/%s/members", org)) link.RawQuery = opt.getURLQuery().Encode() resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &users) return users, resp, err @@ -34,10 +40,13 @@ func (c *Client) ListOrgMembership(org string, opt ListOrgMembershipOption) ([]* // ListPublicOrgMembership list an organization's members func (c *Client) ListPublicOrgMembership(org string, opt ListOrgMembershipOption) ([]*User, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } opt.setDefaults() users := make([]*User, 0, opt.PageSize) - link, _ := url.Parse(fmt.Sprintf("/orgs/%s/public_members", url.PathEscape(org))) + link, _ := url.Parse(fmt.Sprintf("/orgs/%s/public_members", org)) link.RawQuery = opt.getURLQuery().Encode() resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &users) return users, resp, err @@ -45,7 +54,10 @@ func (c *Client) ListPublicOrgMembership(org string, opt ListOrgMembershipOption // CheckOrgMembership Check if a user is a member of an organization func (c *Client) CheckOrgMembership(org, user string) (bool, *Response, error) { - status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) + if err := escapeValidatePathSegments(&org, &user); err != nil { + return false, nil, err + } + status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/members/%s", org, user), nil, nil) if err != nil { return false, resp, err } @@ -61,7 +73,10 @@ func (c *Client) CheckOrgMembership(org, user string) (bool, *Response, error) { // CheckPublicOrgMembership Check if a user is a member of an organization func (c *Client) CheckPublicOrgMembership(org, user string) (bool, *Response, error) { - status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) + if err := escapeValidatePathSegments(&org, &user); err != nil { + return false, nil, err + } + status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/public_members/%s", org, user), nil, nil) if err != nil { return false, resp, err } @@ -77,15 +92,18 @@ func (c *Client) CheckPublicOrgMembership(org, user string) (bool, *Response, er // SetPublicOrgMembership publicize/conceal a user's membership func (c *Client) SetPublicOrgMembership(org, user string, visible bool) (*Response, error) { + if err := escapeValidatePathSegments(&org, &user); err != nil { + return nil, err + } var ( status int err error resp *Response ) if visible { - status, resp, err = c.getStatusCode("PUT", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) + status, resp, err = c.getStatusCode("PUT", fmt.Sprintf("/orgs/%s/public_members/%s", org, user), nil, nil) } else { - status, resp, err = c.getStatusCode("DELETE", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) + status, resp, err = c.getStatusCode("DELETE", fmt.Sprintf("/orgs/%s/public_members/%s", org, user), nil, nil) } if err != nil { return resp, err diff --git a/gitea/org_team.go b/gitea/org_team.go index 148d2c2..0373c6e 100644 --- a/gitea/org_team.go +++ b/gitea/org_team.go @@ -30,6 +30,9 @@ type ListTeamsOptions struct { // ListOrgTeams lists all teams of an organization func (c *Client) ListOrgTeams(org string, opt ListTeamsOptions) ([]*Team, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } opt.setDefaults() teams := make([]*Team, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/teams?%s", org, opt.getURLQuery().Encode()), nil, nil, &teams) @@ -83,6 +86,9 @@ func (opt CreateTeamOption) Validate() error { // CreateTeam creates a team for an organization func (c *Client) CreateTeam(org string, opt CreateTeamOption) (*Team, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -159,6 +165,9 @@ func (c *Client) ListTeamMembers(id int64, opt ListTeamMembersOptions) ([]*User, // GetTeamMember gets a member of a team func (c *Client) GetTeamMember(id int64, user string) (*User, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } m := new(User) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil, m) return m, resp, err @@ -166,12 +175,18 @@ func (c *Client) GetTeamMember(id int64, user string) (*User, *Response, error) // AddTeamMember adds a member to a team func (c *Client) AddTeamMember(id int64, user string) (*Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, err + } _, resp, err := c.getResponse("PUT", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil) return resp, err } // RemoveTeamMember removes a member from a team func (c *Client) RemoveTeamMember(id int64, user string) (*Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil) return resp, err } @@ -191,12 +206,18 @@ func (c *Client) ListTeamRepositories(id int64, opt ListTeamRepositoriesOptions) // AddTeamRepository adds a repository to a team func (c *Client) AddTeamRepository(id int64, org, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&org, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("PUT", fmt.Sprintf("/teams/%d/repos/%s/%s", id, org, repo), nil, nil) return resp, err } // RemoveTeamRepository removes a repository from a team func (c *Client) RemoveTeamRepository(id int64, org, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&org, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d/repos/%s/%s", id, org, repo), nil, nil) return resp, err } diff --git a/gitea/pull.go b/gitea/pull.go index d653746..7c946e8 100644 --- a/gitea/pull.go +++ b/gitea/pull.go @@ -99,6 +99,9 @@ func (opt *ListPullRequestsOptions) QueryEncode() string { // ListRepoPullRequests list PRs of one repository func (c *Client) ListRepoPullRequests(owner, repo string, opt ListPullRequestsOptions) ([]*PullRequest, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() prs := make([]*PullRequest, 0, opt.PageSize) @@ -117,6 +120,9 @@ func (c *Client) ListRepoPullRequests(owner, repo string, opt ListPullRequestsOp // GetPullRequest get information of one PR func (c *Client) GetPullRequest(owner, repo string, index int64) (*PullRequest, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } pr := new(PullRequest) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repo, index), nil, nil, pr) if c.checkServerVersionGreaterThanOrEqual(version1_14_0) != nil { @@ -142,6 +148,9 @@ type CreatePullRequestOption struct { // CreatePullRequest create pull request with options func (c *Client) CreatePullRequest(owner, repo string, opt CreatePullRequestOption) (*PullRequest, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -181,6 +190,9 @@ func (opt EditPullRequestOption) Validate(c *Client) error { // EditPullRequest modify pull request with PR id and options func (c *Client) EditPullRequest(owner, repo string, index int64, opt EditPullRequestOption) (*PullRequest, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(c); err != nil { return nil, nil, err } @@ -214,6 +226,9 @@ func (opt MergePullRequestOption) Validate(c *Client) error { // MergePullRequest merge a PR to repository by PR id func (c *Client) MergePullRequest(owner, repo string, index int64, opt MergePullRequestOption) (bool, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return false, nil, err + } if err := opt.Validate(c); err != nil { return false, nil, err } @@ -230,6 +245,9 @@ func (c *Client) MergePullRequest(owner, repo string, index int64, opt MergePull // IsPullRequestMerged test if one PR is merged to one repository func (c *Client) IsPullRequestMerged(owner, repo string, index int64) (bool, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return false, nil, err + } status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d/merge", owner, repo, index), nil, nil) if err != nil { @@ -241,6 +259,9 @@ func (c *Client) IsPullRequestMerged(owner, repo string, index int64) (bool, *Re // getPullRequestDiffOrPatch gets the patch or diff file as bytes for a PR func (c *Client) getPullRequestDiffOrPatch(owner, repo, kind string, index int64) ([]byte, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &kind); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { r, _, err2 := c.GetRepo(owner, repo) if err2 != nil { diff --git a/gitea/pull_review.go b/gitea/pull_review.go index 41cf729..fa7921b 100644 --- a/gitea/pull_review.go +++ b/gitea/pull_review.go @@ -147,6 +147,9 @@ func (opt CreatePullReviewComment) Validate() error { // ListPullReviews lists all reviews of a pull request func (c *Client) ListPullReviews(owner, repo string, index int64, opt ListPullReviewsOptions) ([]*PullReview, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -162,6 +165,9 @@ func (c *Client) ListPullReviews(owner, repo string, index int64, opt ListPullRe // GetPullReview gets a specific review of a pull request func (c *Client) GetPullReview(owner, repo string, index, id int64) (*PullReview, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -173,6 +179,9 @@ func (c *Client) GetPullReview(owner, repo string, index, id int64) (*PullReview // ListPullReviewComments lists all comments of a pull request review func (c *Client) ListPullReviewComments(owner, repo string, index, id int64) ([]*PullReviewComment, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -185,6 +194,9 @@ func (c *Client) ListPullReviewComments(owner, repo string, index, id int64) ([] // DeletePullReview delete a specific review from a pull request func (c *Client) DeletePullReview(owner, repo string, index, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } @@ -195,6 +207,9 @@ func (c *Client) DeletePullReview(owner, repo string, index, id int64) (*Respons // CreatePullReview create a review to an pull request func (c *Client) CreatePullReview(owner, repo string, index int64, opt CreatePullReviewOptions) (*PullReview, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -215,6 +230,9 @@ func (c *Client) CreatePullReview(owner, repo string, index int64, opt CreatePul // SubmitPullReview submit a pending review to an pull request func (c *Client) SubmitPullReview(owner, repo string, index, id int64, opt SubmitPullReviewOptions) (*PullReview, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -235,6 +253,9 @@ func (c *Client) SubmitPullReview(owner, repo string, index, id int64, opt Submi // CreateReviewRequests create review requests to an pull request func (c *Client) CreateReviewRequests(owner, repo string, index int64, opt PullReviewRequestOptions) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_14_0); err != nil { return nil, err } @@ -251,6 +272,9 @@ func (c *Client) CreateReviewRequests(owner, repo string, index int64, opt PullR // DeleteReviewRequests delete review requests to an pull request func (c *Client) DeleteReviewRequests(owner, repo string, index int64, opt PullReviewRequestOptions) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_14_0); err != nil { return nil, err } @@ -267,6 +291,9 @@ func (c *Client) DeleteReviewRequests(owner, repo string, index int64, opt PullR // DismissPullReview dismiss a review for a pull request func (c *Client) DismissPullReview(owner, repo string, index, id int64, opt DismissPullReviewOptions) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_14_0); err != nil { return nil, err } @@ -283,6 +310,9 @@ func (c *Client) DismissPullReview(owner, repo string, index, id int64, opt Dism // UnDismissPullReview cancel to dismiss a review for a pull request func (c *Client) UnDismissPullReview(owner, repo string, index, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_14_0); err != nil { return nil, err } diff --git a/gitea/release.go b/gitea/release.go index 741cbce..7d36e71 100644 --- a/gitea/release.go +++ b/gitea/release.go @@ -38,32 +38,41 @@ type ListReleasesOptions struct { } // ListReleases list releases of a repository -func (c *Client) ListReleases(user, repo string, opt ListReleasesOptions) ([]*Release, *Response, error) { +func (c *Client) ListReleases(owner, repo string, opt ListReleasesOptions) ([]*Release, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() releases := make([]*Release, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", - fmt.Sprintf("/repos/%s/%s/releases?%s", user, repo, opt.getURLQuery().Encode()), + fmt.Sprintf("/repos/%s/%s/releases?%s", owner, repo, opt.getURLQuery().Encode()), nil, nil, &releases) return releases, resp, err } // GetRelease get a release of a repository by id -func (c *Client) GetRelease(user, repo string, id int64) (*Release, *Response, error) { +func (c *Client) GetRelease(owner, repo string, id int64) (*Release, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } r := new(Release) resp, err := c.getParsedResponse("GET", - fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id), + fmt.Sprintf("/repos/%s/%s/releases/%d", owner, repo, id), jsonHeader, nil, &r) return r, resp, err } // GetReleaseByTag get a release of a repository by tag -func (c *Client) GetReleaseByTag(user, repo string, tag string) (*Release, *Response, error) { +func (c *Client) GetReleaseByTag(owner, repo string, tag string) (*Release, *Response, error) { if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { - return c.fallbackGetReleaseByTag(user, repo, tag) + return c.fallbackGetReleaseByTag(owner, repo, tag) + } + if err := escapeValidatePathSegments(&owner, &repo, &tag); err != nil { + return nil, nil, err } r := new(Release) resp, err := c.getParsedResponse("GET", - fmt.Sprintf("/repos/%s/%s/releases/tags/%s", user, repo, tag), + fmt.Sprintf("/repos/%s/%s/releases/tags/%s", owner, repo, tag), nil, nil, &r) return r, resp, err } @@ -87,7 +96,10 @@ func (opt CreateReleaseOption) Validate() error { } // CreateRelease create a release -func (c *Client) CreateRelease(user, repo string, opt CreateReleaseOption) (*Release, *Response, error) { +func (c *Client) CreateRelease(owner, repo string, opt CreateReleaseOption) (*Release, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := opt.Validate(); err != nil { return nil, nil, err } @@ -97,7 +109,7 @@ func (c *Client) CreateRelease(user, repo string, opt CreateReleaseOption) (*Rel } r := new(Release) resp, err := c.getParsedResponse("POST", - fmt.Sprintf("/repos/%s/%s/releases", user, repo), + fmt.Sprintf("/repos/%s/%s/releases", owner, repo), jsonHeader, bytes.NewReader(body), r) return r, resp, err } @@ -113,20 +125,26 @@ type EditReleaseOption struct { } // EditRelease edit a release -func (c *Client) EditRelease(user, repo string, id int64, form EditReleaseOption) (*Release, *Response, error) { +func (c *Client) EditRelease(owner, repo string, id int64, form EditReleaseOption) (*Release, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(form) if err != nil { return nil, nil, err } r := new(Release) resp, err := c.getParsedResponse("PATCH", - fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id), + fmt.Sprintf("/repos/%s/%s/releases/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), r) return r, resp, err } // DeleteRelease delete a release from a repository, keeping its tag func (c *Client) DeleteRelease(user, repo string, id int64) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id), nil, nil) @@ -135,6 +153,9 @@ func (c *Client) DeleteRelease(user, repo string, id int64) (*Response, error) { // DeleteReleaseByTag deletes a release frm a repository by tag func (c *Client) DeleteReleaseByTag(user, repo string, tag string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &tag); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_14_0); err != nil { return nil, err } @@ -145,9 +166,9 @@ func (c *Client) DeleteReleaseByTag(user, repo string, tag string) (*Response, e } // fallbackGetReleaseByTag is fallback for old gitea installations ( < 1.13.0 ) -func (c *Client) fallbackGetReleaseByTag(user, repo string, tag string) (*Release, *Response, error) { +func (c *Client) fallbackGetReleaseByTag(owner, repo string, tag string) (*Release, *Response, error) { for i := 1; ; i++ { - rl, resp, err := c.ListReleases(user, repo, ListReleasesOptions{ListOptions{Page: i}}) + rl, resp, err := c.ListReleases(owner, repo, ListReleasesOptions{ListOptions{Page: i}}) if err != nil { return nil, resp, err } diff --git a/gitea/repo.go b/gitea/repo.go index 50a1315..67bd956 100644 --- a/gitea/repo.go +++ b/gitea/repo.go @@ -138,6 +138,9 @@ func (c *Client) ListMyRepos(opt ListReposOptions) ([]*Repository, *Response, er // ListUserRepos list all repositories of one user by user's name func (c *Client) ListUserRepos(user string, opt ListReposOptions) ([]*Repository, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } opt.setDefaults() repos := make([]*Repository, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/repos?%s", user, opt.getURLQuery().Encode()), nil, nil, &repos) @@ -151,6 +154,9 @@ type ListOrgReposOptions struct { // ListOrgRepos list all repositories of one organization by organization's name func (c *Client) ListOrgRepos(org string, opt ListOrgReposOptions) ([]*Repository, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } opt.setDefaults() repos := make([]*Repository, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/repos?%s", org, opt.getURLQuery().Encode()), nil, nil, &repos) @@ -351,6 +357,9 @@ func (c *Client) CreateRepo(opt CreateRepoOption) (*Repository, *Response, error // CreateOrgRepo creates an organization repository for authenticated user. func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } if err := opt.Validate(c); err != nil { return nil, nil, err } @@ -365,6 +374,9 @@ func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, * // GetRepo returns information of a repository of given owner. func (c *Client) GetRepo(owner, reponame string) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&owner, &reponame); err != nil { + return nil, nil, err + } repo := new(Repository) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s", owner, reponame), nil, nil, repo) return repo, resp, err @@ -418,6 +430,9 @@ type EditRepoOption struct { // EditRepo edit the properties of a repository func (c *Client) EditRepo(owner, reponame string, opt EditRepoOption) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&owner, &reponame); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -429,18 +444,27 @@ func (c *Client) EditRepo(owner, reponame string, opt EditRepoOption) (*Reposito // DeleteRepo deletes a repository of user or organization. func (c *Client) DeleteRepo(owner, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s", owner, repo), nil, nil) return resp, err } // MirrorSync adds a mirrored repository to the mirror sync queue. func (c *Client) MirrorSync(owner, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/mirror-sync", owner, repo), nil, nil) return resp, err } // GetRepoLanguages return language stats of a repo func (c *Client) GetRepoLanguages(owner, repo string) (map[string]int64, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } langMap := make(map[string]int64) data, resp, err := c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/languages", owner, repo), jsonHeader, nil) @@ -466,7 +490,11 @@ const ( // GetArchive get an archive of a repository by git reference // e.g.: ref -> master, 70b7c74b33, v1.2.1, ... func (c *Client) GetArchive(owner, repo, ref string, ext ArchiveType) ([]byte, *Response, error) { - return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/archive/%s%s", owner, repo, url.PathEscape(ref), ext), nil, nil) + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } + ref = pathEscapeSegments(ref) + return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/archive/%s%s", owner, repo, ref, ext), nil, nil) } // GetArchiveReader gets a `git archive` for a particular tree-ish git reference @@ -474,7 +502,11 @@ func (c *Client) GetArchive(owner, repo, ref string, ext ArchiveType) ([]byte, * // (`v1.2.1`). The archive is returned as a byte stream in a ReadCloser. It is // the responsibility of the client to close the reader. func (c *Client) GetArchiveReader(owner, repo, ref string, ext ArchiveType) (io.ReadCloser, *Response, error) { - resp, err := c.doRequest("GET", fmt.Sprintf("/repos/%s/%s/archive/%s%s", owner, repo, url.PathEscape(ref), ext), nil, nil) + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } + ref = pathEscapeSegments(ref) + resp, err := c.doRequest("GET", fmt.Sprintf("/repos/%s/%s/archive/%s%s", owner, repo, ref, ext), nil, nil) if err != nil { return nil, resp, err } diff --git a/gitea/repo_branch.go b/gitea/repo_branch.go index 6b0eec2..0b7e873 100644 --- a/gitea/repo_branch.go +++ b/gitea/repo_branch.go @@ -20,9 +20,6 @@ type PayloadUser struct { UserName string `json:"username"` } -// FIXME: consider using same format as API when commits API are added. -// applies to PayloadCommit and PayloadCommitVerification - // PayloadCommit represents a commit type PayloadCommit struct { // sha1 hash of the commit @@ -66,6 +63,9 @@ type ListRepoBranchesOptions struct { // ListRepoBranches list all the branches of one repository func (c *Client) ListRepoBranches(user, repo string, opt ListRepoBranchesOptions) ([]*Branch, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() branches := make([]*Branch, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &branches) @@ -74,6 +74,9 @@ func (c *Client) ListRepoBranches(user, repo string, opt ListRepoBranchesOptions // GetRepoBranch get one branch's information of one repository func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &branch); err != nil { + return nil, nil, err + } b := new(Branch) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil, &b) if err != nil { @@ -84,6 +87,9 @@ func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, *Response, e // DeleteRepoBranch delete a branch in a repository func (c *Client) DeleteRepoBranch(user, repo, branch string) (bool, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &branch); err != nil { + return false, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return false, nil, err } @@ -118,6 +124,9 @@ func (opt CreateBranchOption) Validate() error { // CreateBranch creates a branch for a user's repository func (c *Client) CreateBranch(owner, repo string, opt CreateBranchOption) (*Branch, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, nil, err } diff --git a/gitea/repo_branch_protection.go b/gitea/repo_branch_protection.go index 3e1d01a..22bd7b9 100644 --- a/gitea/repo_branch_protection.go +++ b/gitea/repo_branch_protection.go @@ -95,6 +95,9 @@ type ListBranchProtectionsOptions struct { // ListBranchProtections list branch protections for a repo func (c *Client) ListBranchProtections(owner, repo string, opt ListBranchProtectionsOptions) ([]*BranchProtection, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -107,6 +110,9 @@ func (c *Client) ListBranchProtections(owner, repo string, opt ListBranchProtect // GetBranchProtection gets a branch protection func (c *Client) GetBranchProtection(owner, repo, name string) (*BranchProtection, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &name); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -117,6 +123,9 @@ func (c *Client) GetBranchProtection(owner, repo, name string) (*BranchProtectio // CreateBranchProtection creates a branch protection for a repo func (c *Client) CreateBranchProtection(owner, repo string, opt CreateBranchProtectionOption) (*BranchProtection, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -131,6 +140,9 @@ func (c *Client) CreateBranchProtection(owner, repo string, opt CreateBranchProt // EditBranchProtection edits a branch protection for a repo func (c *Client) EditBranchProtection(owner, repo, name string, opt EditBranchProtectionOption) (*BranchProtection, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &name); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -145,6 +157,9 @@ func (c *Client) EditBranchProtection(owner, repo, name string, opt EditBranchPr // DeleteBranchProtection deletes a branch protection for a repo func (c *Client) DeleteBranchProtection(owner, repo, name string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &name); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } diff --git a/gitea/repo_collaborator.go b/gitea/repo_collaborator.go index 63c4eaf..2019e22 100644 --- a/gitea/repo_collaborator.go +++ b/gitea/repo_collaborator.go @@ -17,6 +17,9 @@ type ListCollaboratorsOptions struct { // ListCollaborators list a repository's collaborators func (c *Client) ListCollaborators(user, repo string, opt ListCollaboratorsOptions) ([]*User, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() collaborators := make([]*User, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", @@ -27,6 +30,9 @@ func (c *Client) ListCollaborators(user, repo string, opt ListCollaboratorsOptio // IsCollaborator check if a user is a collaborator of a repository func (c *Client) IsCollaborator(user, repo, collaborator string) (bool, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &collaborator); err != nil { + return false, nil, err + } status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil) if err != nil { return false, resp, err @@ -78,6 +84,9 @@ func (opt AddCollaboratorOption) Validate() error { // AddCollaborator add some user as a collaborator of a repository func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollaboratorOption) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &collaborator); err != nil { + return nil, err + } if err := opt.Validate(); err != nil { return nil, err } @@ -91,6 +100,9 @@ func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollabo // DeleteCollaborator remove a collaborator from a repository func (c *Client) DeleteCollaborator(user, repo, collaborator string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &collaborator); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil) return resp, err diff --git a/gitea/repo_commit.go b/gitea/repo_commit.go index 57df8e8..9bb65b3 100644 --- a/gitea/repo_commit.go +++ b/gitea/repo_commit.go @@ -63,6 +63,9 @@ type CommitAffectedFiles struct { // GetSingleCommit returns a single commit func (c *Client) GetSingleCommit(user, repo, commitID string) (*Commit, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &commitID); err != nil { + return nil, nil, err + } commit := new(Commit) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/commits/%s", user, repo, commitID), nil, nil, &commit) return commit, resp, err @@ -86,6 +89,9 @@ func (opt *ListCommitOptions) QueryEncode() string { // ListRepoCommits return list of commits from a repo func (c *Client) ListRepoCommits(user, repo string, opt ListCommitOptions) ([]*Commit, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/commits", user, repo)) opt.setDefaults() commits := make([]*Commit, 0, opt.PageSize) diff --git a/gitea/repo_file.go b/gitea/repo_file.go index bebe95c..6f99ea0 100644 --- a/gitea/repo_file.go +++ b/gitea/repo_file.go @@ -116,19 +116,12 @@ type FileDeleteResponse struct { Verification *PayloadCommitVerification `json:"verification"` } -// pathEscapeSegments escapes segments of a path while not escaping forward slash -func pathEscapeSegments(path string) string { - slice := strings.Split(path, "/") - for index := range slice { - slice[index] = url.PathEscape(slice[index]) - } - escapedPath := strings.Join(slice, "/") - return escapedPath -} - // GetFile downloads a file of repository, ref can be branch/tag/commit. // e.g.: ref -> master, filepath -> README.md (no leading slash) func (c *Client) GetFile(owner, repo, ref, filepath string) ([]byte, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } filepath = pathEscapeSegments(filepath) if c.checkServerVersionGreaterThanOrEqual(version1_14_0) != nil { ref = pathEscapeSegments(ref) @@ -166,17 +159,23 @@ func (c *Client) ListContents(owner, repo, ref, filepath string) ([]*ContentsRes } func (c *Client) getDirOrFileContents(owner, repo, ref, filepath string) ([]byte, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } filepath = pathEscapeSegments(strings.TrimPrefix(filepath, "/")) return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/contents/%s?ref=%s", owner, repo, filepath, url.QueryEscape(ref)), jsonHeader, nil) } // CreateFile create a file in a repository func (c *Client) CreateFile(owner, repo, filepath string, opt CreateFileOptions) (*FileResponse, *Response, error) { - filepath = pathEscapeSegments(filepath) var err error if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil { return nil, nil, err } + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } + filepath = pathEscapeSegments(filepath) body, err := json.Marshal(&opt) if err != nil { @@ -189,12 +188,16 @@ func (c *Client) CreateFile(owner, repo, filepath string, opt CreateFileOptions) // UpdateFile update a file in a repository func (c *Client) UpdateFile(owner, repo, filepath string, opt UpdateFileOptions) (*FileResponse, *Response, error) { - filepath = pathEscapeSegments(filepath) var err error if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil { return nil, nil, err } + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } + filepath = pathEscapeSegments(filepath) + body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -206,11 +209,14 @@ func (c *Client) UpdateFile(owner, repo, filepath string, opt UpdateFileOptions) // DeleteFile delete a file from repository func (c *Client) DeleteFile(owner, repo, filepath string, opt DeleteFileOptions) (*Response, error) { - filepath = pathEscapeSegments(filepath) var err error if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil { return nil, err } + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } + filepath = pathEscapeSegments(filepath) body, err := json.Marshal(&opt) if err != nil { diff --git a/gitea/repo_key.go b/gitea/repo_key.go index cfdfe0c..ee2ff40 100644 --- a/gitea/repo_key.go +++ b/gitea/repo_key.go @@ -46,6 +46,9 @@ func (opt *ListDeployKeysOptions) QueryEncode() string { // ListDeployKeys list all the deploy keys of one repository func (c *Client) ListDeployKeys(user, repo string, opt ListDeployKeysOptions) ([]*DeployKey, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/keys", user, repo)) opt.setDefaults() link.RawQuery = opt.QueryEncode() @@ -56,6 +59,9 @@ func (c *Client) ListDeployKeys(user, repo string, opt ListDeployKeysOptions) ([ // GetDeployKey get one deploy key with key id func (c *Client) GetDeployKey(user, repo string, keyID int64) (*DeployKey, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } key := new(DeployKey) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys/%d", user, repo, keyID), nil, nil, &key) return key, resp, err @@ -63,6 +69,9 @@ func (c *Client) GetDeployKey(user, repo string, keyID int64) (*DeployKey, *Resp // CreateDeployKey options when create one deploy key func (c *Client) CreateDeployKey(user, repo string, opt CreateKeyOption) (*DeployKey, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opt) if err != nil { return nil, nil, err @@ -74,6 +83,9 @@ func (c *Client) CreateDeployKey(user, repo string, opt CreateKeyOption) (*Deplo // DeleteDeployKey delete deploy key with key id func (c *Client) DeleteDeployKey(owner, repo string, keyID int64) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/keys/%d", owner, repo, keyID), nil, nil) return resp, err } diff --git a/gitea/repo_refs.go b/gitea/repo_refs.go index fa1698a..c954a80 100644 --- a/gitea/repo_refs.go +++ b/gitea/repo_refs.go @@ -27,7 +27,11 @@ type GitObject struct { // GetRepoRef get one ref's information of one repository func (c *Client) GetRepoRef(user, repo, ref string) (*Reference, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } ref = strings.TrimPrefix(ref, "refs/") + ref = pathEscapeSegments(ref) r := new(Reference) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/refs/%s", user, repo, ref), nil, nil, &r) if _, ok := err.(*json.UnmarshalTypeError); ok { @@ -42,7 +46,12 @@ func (c *Client) GetRepoRef(user, repo, ref string) (*Reference, *Response, erro // GetRepoRefs get list of ref's information of one repository func (c *Client) GetRepoRefs(user, repo, ref string) ([]*Reference, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } ref = strings.TrimPrefix(ref, "refs/") + ref = pathEscapeSegments(ref) + data, resp, err := c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/git/refs/%s", user, repo, ref), nil, nil) if err != nil { return nil, resp, err diff --git a/gitea/repo_stars.go b/gitea/repo_stars.go index b4bd981..01243c2 100644 --- a/gitea/repo_stars.go +++ b/gitea/repo_stars.go @@ -16,6 +16,9 @@ type ListStargazersOptions struct { // ListRepoStargazers list a repository's stargazers func (c *Client) ListRepoStargazers(user, repo string, opt ListStargazersOptions) ([]*User, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() stargazers := make([]*User, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/stargazers?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &stargazers) @@ -24,6 +27,9 @@ func (c *Client) ListRepoStargazers(user, repo string, opt ListStargazersOptions // GetStarredRepos returns the repos that the given user has starred func (c *Client) GetStarredRepos(user string) ([]*Repository, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } repos := make([]*Repository, 0, 10) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/starred", user), jsonHeader, nil, &repos) return repos, resp, err @@ -38,6 +44,9 @@ func (c *Client) GetMyStarredRepos() ([]*Repository, *Response, error) { // IsRepoStarring returns whether the authenticated user has starred the repo or not func (c *Client) IsRepoStarring(user, repo string) (bool, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return false, nil, err + } _, resp, err := c.getResponse("GET", fmt.Sprintf("/user/starred/%s/%s", user, repo), jsonHeader, nil) if resp != nil { switch resp.StatusCode { @@ -54,6 +63,9 @@ func (c *Client) IsRepoStarring(user, repo string) (bool, *Response, error) { // StarRepo star specified repo as the authenticated user func (c *Client) StarRepo(user, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("PUT", fmt.Sprintf("/user/starred/%s/%s", user, repo), jsonHeader, nil) if resp != nil { switch resp.StatusCode { @@ -68,6 +80,9 @@ func (c *Client) StarRepo(user, repo string) (*Response, error) { // UnStarRepo remove star to specified repo as the authenticated user func (c *Client) UnStarRepo(user, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/starred/%s/%s", user, repo), jsonHeader, nil) if resp != nil { switch resp.StatusCode { diff --git a/gitea/repo_tag.go b/gitea/repo_tag.go index 6565fa7..0a3c806 100644 --- a/gitea/repo_tag.go +++ b/gitea/repo_tag.go @@ -24,6 +24,9 @@ type ListRepoTagsOptions struct { // ListRepoTags list all the branches of one repository func (c *Client) ListRepoTags(user, repo string, opt ListRepoTagsOptions) ([]*Tag, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() tags := make([]*Tag, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/tags?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &tags) @@ -32,6 +35,9 @@ func (c *Client) ListRepoTags(user, repo string, opt ListRepoTagsOptions) ([]*Ta // DeleteTag deletes a tag from a repository, if no release refers to it func (c *Client) DeleteTag(user, repo string, tag string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &tag); err != nil { + return nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_14_0); err != nil { return nil, err } diff --git a/gitea/repo_topics.go b/gitea/repo_topics.go index fd05d08..92f2228 100644 --- a/gitea/repo_topics.go +++ b/gitea/repo_topics.go @@ -22,6 +22,9 @@ type topicsList struct { // ListRepoTopics list all repository's topics func (c *Client) ListRepoTopics(user, repo string, opt ListRepoTopicsOptions) ([]string, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } opt.setDefaults() list := new(topicsList) @@ -34,9 +37,10 @@ func (c *Client) ListRepoTopics(user, repo string, opt ListRepoTopicsOptions) ([ // SetRepoTopics replaces the list of repo's topics func (c *Client) SetRepoTopics(user, repo string, list []string) (*Response, error) { - + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, err + } l := topicsList{Topics: list} - body, err := json.Marshal(&l) if err != nil { return nil, err @@ -47,12 +51,18 @@ func (c *Client) SetRepoTopics(user, repo string, list []string) (*Response, err // AddRepoTopic adds a topic to a repo's topics list func (c *Client) AddRepoTopic(user, repo, topic string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &topic); err != nil { + return nil, err + } _, resp, err := c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/topics/%s", user, repo, topic), nil, nil) return resp, err } // DeleteRepoTopic deletes a topic from repo's topics list func (c *Client) DeleteRepoTopic(user, repo, topic string) (*Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &topic); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/topics/%s", user, repo, topic), nil, nil) return resp, err } diff --git a/gitea/repo_transfer.go b/gitea/repo_transfer.go index d8d661b..be06010 100644 --- a/gitea/repo_transfer.go +++ b/gitea/repo_transfer.go @@ -20,6 +20,9 @@ type TransferRepoOption struct { // TransferRepo transfers the ownership of a repository func (c *Client) TransferRepo(owner, reponame string, opt TransferRepoOption) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&owner, &reponame); err != nil { + return nil, nil, err + } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } diff --git a/gitea/repo_tree.go b/gitea/repo_tree.go index ce36e46..452394a 100644 --- a/gitea/repo_tree.go +++ b/gitea/repo_tree.go @@ -31,6 +31,9 @@ type GitTreeResponse struct { // GetTrees downloads a file of repository, ref can be branch/tag/commit. // e.g.: ref -> master, tree -> macaron.go(no leading slash) func (c *Client) GetTrees(user, repo, ref string, recursive bool) (*GitTreeResponse, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &ref); err != nil { + return nil, nil, err + } trees := new(GitTreeResponse) var path = fmt.Sprintf("/repos/%s/%s/git/trees/%s", user, repo, ref) if recursive { diff --git a/gitea/repo_watch.go b/gitea/repo_watch.go index 7358705..f499aff 100644 --- a/gitea/repo_watch.go +++ b/gitea/repo_watch.go @@ -22,6 +22,9 @@ type WatchInfo struct { // GetWatchedRepos list all the watched repos of user func (c *Client) GetWatchedRepos(user string) ([]*Repository, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } repos := make([]*Repository, 0, 10) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/subscriptions", user), nil, nil, &repos) return repos, resp, err @@ -35,8 +38,11 @@ func (c *Client) GetMyWatchedRepos() ([]*Repository, *Response, error) { } // CheckRepoWatch check if the current user is watching a repo -func (c *Client) CheckRepoWatch(repoUser, repoName string) (bool, *Response, error) { - status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil) +func (c *Client) CheckRepoWatch(owner, repo string) (bool, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return false, nil, err + } + status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/subscription", owner, repo), nil, nil) if err != nil { return false, resp, err } @@ -51,8 +57,11 @@ func (c *Client) CheckRepoWatch(repoUser, repoName string) (bool, *Response, err } // WatchRepo start to watch a repository -func (c *Client) WatchRepo(repoUser, repoName string) (*Response, error) { - status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil) +func (c *Client) WatchRepo(owner, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } + status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/subscription", owner, repo), nil, nil) if err != nil { return resp, err } @@ -63,8 +72,11 @@ func (c *Client) WatchRepo(repoUser, repoName string) (*Response, error) { } // UnWatchRepo stop to watch a repository -func (c *Client) UnWatchRepo(repoUser, repoName string) (*Response, error) { - status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil) +func (c *Client) UnWatchRepo(owner, repo string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, err + } + status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/subscription", owner, repo), nil, nil) if err != nil { return resp, err } diff --git a/gitea/status.go b/gitea/status.go index be43655..fe5d971 100644 --- a/gitea/status.go +++ b/gitea/status.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/json" "fmt" + "net/url" "time" ) @@ -51,12 +52,15 @@ type CreateStatusOption struct { // CreateStatus creates a new Status for a given Commit func (c *Client) CreateStatus(owner, repo, sha string, opts CreateStatusOption) (*Status, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } body, err := json.Marshal(&opts) if err != nil { return nil, nil, err } status := new(Status) - resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/statuses/%s", owner, repo, sha), jsonHeader, bytes.NewReader(body), status) + resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/statuses/%s", owner, repo, url.QueryEscape(sha)), jsonHeader, bytes.NewReader(body), status) return status, resp, err } @@ -67,6 +71,9 @@ type ListStatusesOption struct { // ListStatuses returns all statuses for a given Commit by ref func (c *Client) ListStatuses(owner, repo, ref string, opt ListStatusesOption) ([]*Status, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &ref); err != nil { + return nil, nil, err + } opt.setDefaults() statuses := make([]*Status, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s/statuses?%s", owner, repo, ref, opt.getURLQuery().Encode()), jsonHeader, nil, &statuses) @@ -86,6 +93,9 @@ type CombinedStatus struct { // GetCombinedStatus returns the CombinedStatus for a given Commit func (c *Client) GetCombinedStatus(owner, repo, ref string) (*CombinedStatus, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo, &ref); err != nil { + return nil, nil, err + } status := new(CombinedStatus) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s/status", owner, repo, ref), jsonHeader, nil, status) diff --git a/gitea/user.go b/gitea/user.go index e909c68..2095236 100644 --- a/gitea/user.go +++ b/gitea/user.go @@ -30,6 +30,9 @@ type User struct { // GetUserInfo get user info by user's name func (c *Client) GetUserInfo(user string) (*User, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } u := new(User) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s", user), nil, nil, u) return u, resp, err diff --git a/gitea/user_app.go b/gitea/user_app.go index cf6c3cf..2921eea 100644 --- a/gitea/user_app.go +++ b/gitea/user_app.go @@ -9,6 +9,7 @@ import ( "bytes" "encoding/json" "fmt" + "net/url" "reflect" ) @@ -35,7 +36,7 @@ func (c *Client) ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, } opts.setDefaults() tokens := make([]*AccessToken, 0, opts.PageSize) - resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/tokens?%s", username, opts.getURLQuery().Encode()), jsonHeader, nil, &tokens) + resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/tokens?%s", url.PathEscape(username), opts.getURLQuery().Encode()), jsonHeader, nil, &tokens) return tokens, resp, err } @@ -57,7 +58,7 @@ func (c *Client) CreateAccessToken(opt CreateAccessTokenOption) (*AccessToken, * return nil, nil, err } t := new(AccessToken) - resp, err := c.getParsedResponse("POST", fmt.Sprintf("/users/%s/tokens", username), jsonHeader, bytes.NewReader(body), t) + resp, err := c.getParsedResponse("POST", fmt.Sprintf("/users/%s/tokens", url.PathEscape(username)), jsonHeader, bytes.NewReader(body), t) return t, resp, err } @@ -84,6 +85,6 @@ func (c *Client) DeleteAccessToken(value interface{}) (*Response, error) { return nil, fmt.Errorf("only string and int64 supported") } - _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/users/%s/tokens/%s", username, token), jsonHeader, nil) + _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/users/%s/tokens/%s", url.PathEscape(username), url.PathEscape(token)), jsonHeader, nil) return resp, err } diff --git a/gitea/user_follow.go b/gitea/user_follow.go index c8bafc0..7bd340c 100644 --- a/gitea/user_follow.go +++ b/gitea/user_follow.go @@ -21,6 +21,9 @@ func (c *Client) ListMyFollowers(opt ListFollowersOptions) ([]*User, *Response, // ListFollowers list all the followers of one user func (c *Client) ListFollowers(user string, opt ListFollowersOptions) ([]*User, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } opt.setDefaults() users := make([]*User, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/followers?%s", user, opt.getURLQuery().Encode()), nil, nil, &users) @@ -42,6 +45,9 @@ func (c *Client) ListMyFollowing(opt ListFollowingOptions) ([]*User, *Response, // ListFollowing list all the users the user followed func (c *Client) ListFollowing(user string, opt ListFollowingOptions) ([]*User, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } opt.setDefaults() users := make([]*User, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/following?%s", user, opt.getURLQuery().Encode()), nil, nil, &users) @@ -50,24 +56,38 @@ func (c *Client) ListFollowing(user string, opt ListFollowingOptions) ([]*User, // IsFollowing if current user followed the target func (c *Client) IsFollowing(target string) (bool, *Response) { + if err := escapeValidatePathSegments(&target); err != nil { + // ToDo return err + return false, nil + } _, resp, err := c.getResponse("GET", fmt.Sprintf("/user/following/%s", target), nil, nil) return err == nil, resp } // IsUserFollowing if the user followed the target func (c *Client) IsUserFollowing(user, target string) (bool, *Response) { + if err := escapeValidatePathSegments(&user, &target); err != nil { + // ToDo return err + return false, nil + } _, resp, err := c.getResponse("GET", fmt.Sprintf("/users/%s/following/%s", user, target), nil, nil) return err == nil, resp } // Follow set current user follow the target func (c *Client) Follow(target string) (*Response, error) { + if err := escapeValidatePathSegments(&target); err != nil { + return nil, err + } _, resp, err := c.getResponse("PUT", fmt.Sprintf("/user/following/%s", target), nil, nil) return resp, err } // Unfollow set current user unfollow the target func (c *Client) Unfollow(target string) (*Response, error) { + if err := escapeValidatePathSegments(&target); err != nil { + return nil, err + } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/following/%s", target), nil, nil) return resp, err } diff --git a/gitea/user_gpgkey.go b/gitea/user_gpgkey.go index d3d64b4..6c1b9d1 100644 --- a/gitea/user_gpgkey.go +++ b/gitea/user_gpgkey.go @@ -40,6 +40,9 @@ type ListGPGKeysOptions struct { // ListGPGKeys list all the GPG keys of the user func (c *Client) ListGPGKeys(user string, opt ListGPGKeysOptions) ([]*GPGKey, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } opt.setDefaults() keys := make([]*GPGKey, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/gpg_keys?%s", user, opt.getURLQuery().Encode()), nil, nil, &keys) diff --git a/gitea/user_key.go b/gitea/user_key.go index d005f00..02795ba 100644 --- a/gitea/user_key.go +++ b/gitea/user_key.go @@ -31,6 +31,9 @@ type ListPublicKeysOptions struct { // ListPublicKeys list all the public keys of the user func (c *Client) ListPublicKeys(user string, opt ListPublicKeysOptions) ([]*PublicKey, *Response, error) { + if err := escapeValidatePathSegments(&user); err != nil { + return nil, nil, err + } opt.setDefaults() keys := make([]*PublicKey, 0, opt.PageSize) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/keys?%s", user, opt.getURLQuery().Encode()), nil, nil, &keys)