diff --git a/go.mod b/go.mod index 8787bc0f1f2..70b0e97f0bf 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ replace ( ) require ( - code.gitea.io/sdk/gitea v0.15.1 + code.gitea.io/sdk/gitea v0.16.0 github.com/goccy/kpoward v0.1.0 github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230625233257-b8504803389b github.com/sigstore/sigstore/pkg/signature/kms/aws v1.7.3 @@ -92,8 +92,10 @@ require ( github.com/cloudflare/circl v1.3.3 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/davidmz/go-pageant v1.0.2 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/fatih/color v1.13.0 // indirect + github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.0.0 // indirect diff --git a/go.sum b/go.sum index 63d06baa5ca..2a0cf668c8e 100644 --- a/go.sum +++ b/go.sum @@ -47,9 +47,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= -code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= -code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= +code.gitea.io/sdk/gitea v0.16.0 h1:gAfssETO1Hv9QbE+/nhWu7EjoFQYKt6kPoyDytQgw00= +code.gitea.io/sdk/gitea v0.16.0/go.mod h1:ndkDk99BnfiUCCYEUhpNzi0lpmApXlwRFqClBlOlEBg= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d h1:LblfooH1lKOpp1hIhukktmSAxFkqMPFk9KR6iZ0MJNI= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= contrib.go.opencensus.io/exporter/prometheus v0.4.0 h1:0QfIkj9z/iVZgK31D9H9ohjjIDApI2GOPScCKwxedbs= @@ -377,6 +376,8 @@ github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnG github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= +github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -456,6 +457,8 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= +github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= @@ -693,7 +696,7 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -1217,10 +1220,12 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= @@ -1557,7 +1562,6 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= diff --git a/vendor/code.gitea.io/sdk/gitea/agent.go b/vendor/code.gitea.io/sdk/gitea/agent.go new file mode 100644 index 00000000000..7622ece788d --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/agent.go @@ -0,0 +1,38 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build !windows + +package gitea + +import ( + "fmt" + "net" + "os" + + "golang.org/x/crypto/ssh/agent" +) + +// hasAgent returns true if the ssh agent is available +func hasAgent() bool { + if _, err := os.Stat(os.Getenv("SSH_AUTH_SOCK")); err != nil { + return false + } + + return true +} + +// GetAgent returns a ssh agent +func GetAgent() (agent.Agent, error) { + if !hasAgent() { + return nil, fmt.Errorf("no ssh agent available") + } + + sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) + if err != nil { + return nil, err + } + + return agent.NewClient(sshAgent), nil +} diff --git a/vendor/code.gitea.io/sdk/gitea/agent_windows.go b/vendor/code.gitea.io/sdk/gitea/agent_windows.go new file mode 100644 index 00000000000..135dc4ffcb2 --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/agent_windows.go @@ -0,0 +1,28 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build windows + +package gitea + +import ( + "fmt" + + "github.com/davidmz/go-pageant" + "golang.org/x/crypto/ssh/agent" +) + +// hasAgent returns true if pageant is available +func hasAgent() bool { + return pageant.Available() +} + +// GetAgent returns a ssh agent +func GetAgent() (agent.Agent, error) { + if !hasAgent() { + return nil, fmt.Errorf("no pageant available") + } + + return pageant.New(), nil +} diff --git a/vendor/code.gitea.io/sdk/gitea/attachment.go b/vendor/code.gitea.io/sdk/gitea/attachment.go index 24c57baf4b0..f02c7214187 100644 --- a/vendor/code.gitea.io/sdk/gitea/attachment.go +++ b/vendor/code.gitea.io/sdk/gitea/attachment.go @@ -43,7 +43,7 @@ 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) { +func (c *Client) GetReleaseAttachment(user, repo string, release, id int64) (*Attachment, *Response, error) { if err := escapeValidatePathSegments(&user, &repo); err != nil { return nil, nil, err } @@ -88,7 +88,7 @@ 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) { +func (c *Client) EditReleaseAttachment(user, repo string, release, attachment int64, form EditAttachmentOptions) (*Attachment, *Response, error) { if err := escapeValidatePathSegments(&user, &repo); err != nil { return nil, nil, err } @@ -102,7 +102,7 @@ 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) { +func (c *Client) DeleteReleaseAttachment(user, repo string, release, id int64) (*Response, error) { if err := escapeValidatePathSegments(&user, &repo); err != nil { return nil, err } diff --git a/vendor/code.gitea.io/sdk/gitea/client.go b/vendor/code.gitea.io/sdk/gitea/client.go index 3fe3e8bd779..22f0eedd4d8 100644 --- a/vendor/code.gitea.io/sdk/gitea/client.go +++ b/vendor/code.gitea.io/sdk/gitea/client.go @@ -6,6 +6,7 @@ package gitea import ( + "bytes" "context" "encoding/json" "errors" @@ -24,22 +25,22 @@ var jsonHeader = http.Header{"content-type": []string{"application/json"}} // Version return the library version func Version() string { - return "0.15.1" + return "0.16.0" } // Client represents a thread-safe Gitea API client. type Client struct { - url string - accessToken string - username string - password string - otp string - sudo string - debug bool - client *http.Client - ctx context.Context - mutex sync.RWMutex - + url string + accessToken string + username string + password string + otp string + sudo string + debug bool + httpsigner *HTTPSign + client *http.Client + ctx context.Context + mutex sync.RWMutex serverVersion *version.Version getVersionOnce sync.Once ignoreVersion bool // only set by SetGiteaVersion so don't need a mutex lock @@ -67,8 +68,12 @@ func NewClient(url string, options ...ClientOption) (*Client, error) { } } if err := client.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { + if errors.Is(err, &ErrUnknownVersion{}) { + return client, err + } return nil, err } + return client, nil } @@ -112,6 +117,52 @@ func SetBasicAuth(username, password string) ClientOption { } } +// UseSSHCert is an option for NewClient to enable SSH certificate authentication via HTTPSign +// If you want to auth against the ssh-agent you'll need to set a principal, if you want to +// use a file on disk you'll need to specify sshKey. +// If you have an encrypted sshKey you'll need to also set the passphrase. +func UseSSHCert(principal, sshKey, passphrase string) ClientOption { + return func(client *Client) error { + if err := client.checkServerVersionGreaterThanOrEqual(version1_17_0); err != nil { + return err + } + + client.mutex.Lock() + defer client.mutex.Unlock() + + var err error + client.httpsigner, err = NewHTTPSignWithCert(principal, sshKey, passphrase) + if err != nil { + return err + } + + return nil + } +} + +// UseSSHPubkey is an option for NewClient to enable SSH pubkey authentication via HTTPSign +// If you want to auth against the ssh-agent you'll need to set a fingerprint, if you want to +// use a file on disk you'll need to specify sshKey. +// If you have an encrypted sshKey you'll need to also set the passphrase. +func UseSSHPubkey(fingerprint, sshKey, passphrase string) ClientOption { + return func(client *Client) error { + if err := client.checkServerVersionGreaterThanOrEqual(version1_17_0); err != nil { + return err + } + + client.mutex.Lock() + defer client.mutex.Unlock() + + var err error + client.httpsigner, err = NewHTTPSignWithPubkey(fingerprint, sshKey, passphrase) + if err != nil { + return err + } + + return nil + } +} + // SetBasicAuth sets username and password func (c *Client) SetBasicAuth(username, password string) { c.mutex.Lock() @@ -199,14 +250,20 @@ func (c *Client) getWebResponse(method, path string, body io.Reader) ([]byte, *R if debug { fmt.Printf("Response: %v\n\n", resp) } - return data, &Response{resp}, nil + return data, &Response{resp}, err } func (c *Client) doRequest(method, path string, header http.Header, body io.Reader) (*Response, error) { c.mutex.RLock() debug := c.debug if debug { - fmt.Printf("%s: %s\nHeader: %v\nBody: %s\n", method, c.url+"/api/v1"+path, header, body) + var bodyStr string + if body != nil { + bs, _ := ioutil.ReadAll(body) + body = bytes.NewReader(bs) + bodyStr = string(bs) + } + fmt.Printf("%s: %s\nHeader: %v\nBody: %s\n", method, c.url+"/api/v1"+path, header, bodyStr) } req, err := http.NewRequestWithContext(c.ctx, method, c.url+"/api/v1"+path, body) if err != nil { @@ -233,6 +290,13 @@ func (c *Client) doRequest(method, path string, header http.Header, body io.Read req.Header[k] = v } + if c.httpsigner != nil { + err = c.SignRequest(req) + if err != nil { + return nil, err + } + } + resp, err := client.Do(req) if err != nil { return nil, err @@ -262,33 +326,44 @@ func statusCodeToErr(resp *Response) (body []byte, err error) { return nil, fmt.Errorf("body read on HTTP error %d: %v", resp.StatusCode, err) } - switch resp.StatusCode { - case 403: - return data, errors.New("403 Forbidden") - case 404: - return data, errors.New("404 Not Found") - case 409: - return data, errors.New("409 Conflict") - case 422: - return data, fmt.Errorf("422 Unprocessable Entity: %s", string(data)) - } - - path := resp.Request.URL.Path - method := resp.Request.Method - header := resp.Request.Header + // Try to unmarshal and get an error message errMap := make(map[string]interface{}) if err = json.Unmarshal(data, &errMap); err != nil { // when the JSON can't be parsed, data was probably empty or a // plain string, so we try to return a helpful error anyway + path := resp.Request.URL.Path + method := resp.Request.Method + header := resp.Request.Header return data, fmt.Errorf("Unknown API Error: %d\nRequest: '%s' with '%s' method '%s' header and '%s' body", resp.StatusCode, path, method, header, string(data)) } - return data, errors.New(errMap["message"].(string)) + + if msg, ok := errMap["message"]; ok { + return data, fmt.Errorf("%v", msg) + } + + // If no error message, at least give status and data + return data, fmt.Errorf("%s: %s", resp.Status, string(data)) +} + +func (c *Client) getResponseReader(method, path string, header http.Header, body io.Reader) (io.ReadCloser, *Response, error) { + resp, err := c.doRequest(method, path, header, body) + if err != nil { + return nil, resp, err + } + + // check for errors + data, err := statusCodeToErr(resp) + if err != nil { + return io.NopCloser(bytes.NewReader(data)), resp, err + } + + return resp.Body, resp, nil } func (c *Client) getResponse(method, path string, header http.Header, body io.Reader) ([]byte, *Response, error) { resp, err := c.doRequest(method, path, header, body) if err != nil { - return nil, nil, err + return nil, resp, err } defer resp.Body.Close() diff --git a/vendor/code.gitea.io/sdk/gitea/doc.go b/vendor/code.gitea.io/sdk/gitea/doc.go index 6bd327db462..777ad2fd1d6 100644 --- a/vendor/code.gitea.io/sdk/gitea/doc.go +++ b/vendor/code.gitea.io/sdk/gitea/doc.go @@ -2,4 +2,8 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. +// Package gitea implements a client for the Gitea API. +// The version corresponds to the highest supported version +// of the gitea API, but backwards-compatibility is mostly +// given. package gitea // import "code.gitea.io/sdk/gitea" diff --git a/vendor/code.gitea.io/sdk/gitea/fork.go b/vendor/code.gitea.io/sdk/gitea/fork.go index c8e5323bc0e..0373c352bc3 100644 --- a/vendor/code.gitea.io/sdk/gitea/fork.go +++ b/vendor/code.gitea.io/sdk/gitea/fork.go @@ -16,7 +16,7 @@ type ListForksOptions struct { } // ListForks list a repository's forks -func (c *Client) ListForks(user string, repo string, opt ListForksOptions) ([]*Repository, *Response, error) { +func (c *Client) ListForks(user, repo string, opt ListForksOptions) ([]*Repository, *Response, error) { if err := escapeValidatePathSegments(&user, &repo); err != nil { return nil, nil, err } @@ -32,6 +32,8 @@ func (c *Client) ListForks(user string, repo string, opt ListForksOptions) ([]*R type CreateForkOption struct { // organization name, if forking into an organization Organization *string `json:"organization"` + // name of the forked repository + Name *string `json:"name"` } // CreateFork create a fork of a repository diff --git a/vendor/code.gitea.io/sdk/gitea/hook_validate.go b/vendor/code.gitea.io/sdk/gitea/hook_validate.go new file mode 100644 index 00000000000..5ef61493817 --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/hook_validate.go @@ -0,0 +1,59 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "io" + "net/http" +) + +// VerifyWebhookSignature verifies that a payload matches the X-Gitea-Signature based on a secret +func VerifyWebhookSignature(secret, expected string, payload []byte) (bool, error) { + hash := hmac.New(sha256.New, []byte(secret)) + if _, err := hash.Write(payload); err != nil { + return false, err + } + expectedSum, err := hex.DecodeString(expected) + if err != nil { + return false, err + } + return hmac.Equal(hash.Sum(nil), expectedSum), nil +} + +// VerifyWebhookSignatureMiddleware is a http.Handler for verifying X-Gitea-Signature on incoming webhooks +func VerifyWebhookSignatureMiddleware(secret string) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var b bytes.Buffer + if _, err := io.Copy(&b, r.Body); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + expected := r.Header.Get("X-Gitea-Signature") + if expected == "" { + http.Error(w, "no signature found", http.StatusBadRequest) + return + } + + ok, err := VerifyWebhookSignature(secret, expected, b.Bytes()) + if err != nil { + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + if !ok { + http.Error(w, "invalid payload", http.StatusUnauthorized) + return + } + + r.Body = io.NopCloser(&b) + next.ServeHTTP(w, r) + }) + } +} diff --git a/vendor/code.gitea.io/sdk/gitea/httpsign.go b/vendor/code.gitea.io/sdk/gitea/httpsign.go new file mode 100644 index 00000000000..49b005954e5 --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/httpsign.go @@ -0,0 +1,253 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "crypto" + "encoding/base64" + "fmt" + "io" + "net/http" + "os" + "strings" + "time" + + "github.com/go-fed/httpsig" + "golang.org/x/crypto/ssh" +) + +// HTTPSign contains the signer used for signing requests +type HTTPSign struct { + ssh.Signer + cert bool +} + +// HTTPSignConfig contains the configuration for creating a HTTPSign +type HTTPSignConfig struct { + fingerprint string + principal string + pubkey bool + cert bool + sshKey string + passphrase string +} + +// NewHTTPSignWithPubkey can be used to create a HTTPSign with a public key +// if no fingerprint is specified it returns the first public key found +func NewHTTPSignWithPubkey(fingerprint, sshKey, passphrase string) (*HTTPSign, error) { + return newHTTPSign(&HTTPSignConfig{ + fingerprint: fingerprint, + pubkey: true, + sshKey: sshKey, + passphrase: passphrase, + }) +} + +// NewHTTPSignWithCert can be used to create a HTTPSign with a certificate +// if no principal is specified it returns the first certificate found +func NewHTTPSignWithCert(principal, sshKey, passphrase string) (*HTTPSign, error) { + return newHTTPSign(&HTTPSignConfig{ + principal: principal, + cert: true, + sshKey: sshKey, + passphrase: passphrase, + }) +} + +// NewHTTPSign returns a new HTTPSign +// It will check the ssh-agent or a local file is config.sshKey is set. +// Depending on the configuration it will either use a certificate or a public key +func newHTTPSign(config *HTTPSignConfig) (*HTTPSign, error) { + var signer ssh.Signer + + if config.sshKey != "" { + priv, err := os.ReadFile(config.sshKey) + if err != nil { + return nil, err + } + + if config.passphrase == "" { + signer, err = ssh.ParsePrivateKey(priv) + if err != nil { + return nil, err + } + } else { + signer, err = ssh.ParsePrivateKeyWithPassphrase(priv, []byte(config.passphrase)) + if err != nil { + return nil, err + } + } + + if config.cert { + certbytes, err := os.ReadFile(config.sshKey + "-cert.pub") + if err != nil { + return nil, err + } + + pub, _, _, _, err := ssh.ParseAuthorizedKey(certbytes) + if err != nil { + return nil, err + } + + cert, ok := pub.(*ssh.Certificate) + if !ok { + return nil, fmt.Errorf("failed to parse certificate") + } + + signer, err = ssh.NewCertSigner(cert, signer) + if err != nil { + return nil, err + } + } + } else { + // if no sshKey is specified, check if we have a ssh-agent and use it + agent, err := GetAgent() + if err != nil { + return nil, err + } + + signers, err := agent.Signers() + if err != nil { + return nil, err + } + + if len(signers) == 0 { + return nil, fmt.Errorf("no signers found") + } + + if config.cert { + signer = findCertSigner(signers, config.principal) + if signer == nil { + return nil, fmt.Errorf("no certificate found for %s", config.principal) + } + } + + if config.pubkey { + signer = findPubkeySigner(signers, config.fingerprint) + if signer == nil { + return nil, fmt.Errorf("no public key found for %s", config.fingerprint) + } + } + } + + return &HTTPSign{ + Signer: signer, + cert: config.cert, + }, nil +} + +// SignRequest signs a HTTP request +func (c *Client) SignRequest(r *http.Request) error { + var contents []byte + + headersToSign := []string{httpsig.RequestTarget, "(created)", "(expires)"} + + if c.httpsigner.cert { + // add our certificate to the headers to sign + pubkey, _ := ssh.ParsePublicKey(c.httpsigner.Signer.PublicKey().Marshal()) + if cert, ok := pubkey.(*ssh.Certificate); ok { + certString := base64.RawStdEncoding.EncodeToString(cert.Marshal()) + r.Header.Add("x-ssh-certificate", certString) + + headersToSign = append(headersToSign, "x-ssh-certificate") + } else { + return fmt.Errorf("no ssh certificate found") + } + } + + // if we have a body, the Digest header will be added and we'll include this also in + // our signature. + if r.Body != nil { + body, err := r.GetBody() + if err != nil { + return fmt.Errorf("getBody() failed: %s", err) + } + + contents, err = io.ReadAll(body) + if err != nil { + return fmt.Errorf("failed reading body: %s", err) + } + + headersToSign = append(headersToSign, "Digest") + } + + // create a signer for the request and headers, the signature will be valid for 10 seconds + signer, _, err := httpsig.NewSSHSigner(c.httpsigner.Signer, httpsig.DigestSha512, headersToSign, httpsig.Signature, 10) + if err != nil { + return fmt.Errorf("httpsig.NewSSHSigner failed: %s", err) + } + + // sign the request, use the fingerprint if we don't have a certificate + keyID := "gitea" + if !c.httpsigner.cert { + keyID = ssh.FingerprintSHA256(c.httpsigner.Signer.PublicKey()) + } + + err = signer.SignRequest(keyID, r, contents) + if err != nil { + return fmt.Errorf("httpsig.Signrequest failed: %s", err) + } + + return nil +} + +// findCertSigner returns the Signer containing a valid certificate +// if no principal is specified it returns the first certificate found +func findCertSigner(sshsigners []ssh.Signer, principal string) ssh.Signer { + for _, s := range sshsigners { + // Check if the key is a certificate + if !strings.Contains(s.PublicKey().Type(), "cert-v01@openssh.com") { + continue + } + + // convert the ssh.Signer to a ssh.Certificate + mpubkey, _ := ssh.ParsePublicKey(s.PublicKey().Marshal()) + cryptopub := mpubkey.(crypto.PublicKey) + cert := cryptopub.(*ssh.Certificate) + t := time.Unix(int64(cert.ValidBefore), 0) + + // make sure the certificate is at least 10 seconds valid + if time.Until(t) <= time.Second*10 { + continue + } + + if principal == "" { + return s + } + + for _, p := range cert.ValidPrincipals { + if p == principal { + return s + } + } + } + + return nil +} + +// findPubkeySigner returns the Signer containing a valid public key +// if no fingerprint is specified it returns the first public key found +func findPubkeySigner(sshsigners []ssh.Signer, fingerprint string) ssh.Signer { + for _, s := range sshsigners { + // Check if the key is a certificate + if strings.Contains(s.PublicKey().Type(), "cert-v01@openssh.com") { + continue + } + + if fingerprint == "" { + return s + } + + if strings.TrimSpace(string(ssh.MarshalAuthorizedKey(s.PublicKey()))) == fingerprint { + return s + } + + if ssh.FingerprintSHA256(s.PublicKey()) == fingerprint { + return s + } + } + + return nil +} diff --git a/vendor/code.gitea.io/sdk/gitea/issue.go b/vendor/code.gitea.io/sdk/gitea/issue.go index c33856a4da4..603d23de2d4 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue.go +++ b/vendor/code.gitea.io/sdk/gitea/issue.go @@ -71,6 +71,10 @@ type ListIssueOption struct { AssignedBy string // filter by username mentioned MentionedBy string + // filter by owner (only works on ListIssues on User) + Owner string + // filter by team (requires organization owner parameter to be provided and only works on ListIssues on User) + Team string } // StateType issue state type @@ -135,6 +139,12 @@ func (opt *ListIssueOption) QueryEncode() string { if len(opt.MentionedBy) > 0 { query.Add("mentioned_by", opt.MentionedBy) } + if len(opt.Owner) > 0 { + query.Add("owner", opt.Owner) + } + if len(opt.Team) > 0 { + query.Add("team", opt.MentionedBy) + } return query.Encode() } @@ -279,6 +289,17 @@ func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption) return issue, resp, err } +// DeleteIssue delete a issue from a repository +func (c *Client) DeleteIssue(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/issues/%d", user, repo, id), + nil, nil) + return resp, err +} + func (c *Client) issueBackwardsCompatibility(issue *Issue) { if c.checkServerVersionGreaterThanOrEqual(version1_12_0) != nil { c.mutex.RLock() diff --git a/vendor/code.gitea.io/sdk/gitea/issue_milestone.go b/vendor/code.gitea.io/sdk/gitea/issue_milestone.go index dfb5720a0c3..4e0d79a9f93 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue_milestone.go +++ b/vendor/code.gitea.io/sdk/gitea/issue_milestone.go @@ -72,7 +72,7 @@ func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, *Respon } // GetMilestoneByName get one milestone by repo and milestone name -func (c *Client) GetMilestoneByName(owner, repo string, name string) (*Milestone, *Response, error) { +func (c *Client) GetMilestoneByName(owner, repo, name string) (*Milestone, *Response, error) { if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { // backwards compatibility mode m, resp, err := c.resolveMilestoneByName(owner, repo, name) @@ -163,7 +163,7 @@ func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOp } // EditMilestoneByName modify milestone with options -func (c *Client) EditMilestoneByName(owner, repo string, name string, opt EditMilestoneOption) (*Milestone, *Response, error) { +func (c *Client) EditMilestoneByName(owner, repo, name string, opt EditMilestoneOption) (*Milestone, *Response, error) { if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { // backwards compatibility mode m, _, err := c.resolveMilestoneByName(owner, repo, name) @@ -197,7 +197,7 @@ func (c *Client) DeleteMilestone(owner, repo string, id int64) (*Response, error } // DeleteMilestoneByName delete one milestone by name -func (c *Client) DeleteMilestoneByName(owner, repo string, name string) (*Response, error) { +func (c *Client) DeleteMilestoneByName(owner, repo, name string) (*Response, error) { if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { // backwards compatibility mode m, _, err := c.resolveMilestoneByName(owner, repo, name) @@ -229,7 +229,7 @@ func (c *Client) resolveMilestoneByName(owner, repo, name string) (*Milestone, * return nil, nil, fmt.Errorf("milestone '%s' do not exist", name) } for _, m := range miles { - if strings.ToLower(strings.TrimSpace(m.Title)) == strings.ToLower(strings.TrimSpace(name)) { + if strings.EqualFold(strings.TrimSpace(m.Title), strings.TrimSpace(name)) { return m, resp, nil } } diff --git a/vendor/code.gitea.io/sdk/gitea/issue_template.go b/vendor/code.gitea.io/sdk/gitea/issue_template.go new file mode 100644 index 00000000000..e6ac1e97a02 --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/issue_template.go @@ -0,0 +1,97 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "fmt" +) + +// IssueTemplate provides metadata and content on an issue template. +// There are two types of issue templates: .Markdown- and .Form-based. +type IssueTemplate struct { + Name string `json:"name"` + About string `json:"about"` + Filename string `json:"file_name"` + IssueTitle string `json:"title"` + IssueLabels []string `json:"labels"` + IssueRef string `json:"ref"` + // If non-nil, this is a form-based template + Form []IssueFormElement `json:"body"` + // Should only be used when .Form is nil. + MarkdownContent string `json:"content"` +} + +// IssueFormElement describes a part of a IssueTemplate form +type IssueFormElement struct { + ID string `json:"id"` + Type IssueFormElementType `json:"type"` + Attributes IssueFormElementAttributes `json:"attributes"` + Validations IssueFormElementValidations `json:"validations"` +} + +// IssueFormElementAttributes contains the combined set of attributes available on all element types. +type IssueFormElementAttributes struct { + // required for all element types. + // A brief description of the expected user input, which is also displayed in the form. + Label string `json:"label"` + // required for element types "dropdown", "checkboxes" + // for dropdown, contains the available options + Options []string `json:"options"` + // for element types "markdown", "textarea", "input" + // Text that is pre-filled in the input + Value string `json:"value"` + // for element types "textarea", "input", "dropdown", "checkboxes" + // A description of the text area to provide context or guidance, which is displayed in the form. + Description string `json:"description"` + // for element types "textarea", "input" + // A semi-opaque placeholder that renders in the text area when empty. + Placeholder string `json:"placeholder"` + // for element types "textarea" + // A language specifier. If set, the input is rendered as codeblock with syntax highlighting. + SyntaxHighlighting string `json:"render"` + // for element types "dropdown" + Multiple bool `json:"multiple"` +} + +// IssueFormElementValidations contains the combined set of validations available on all element types. +type IssueFormElementValidations struct { + // for all element types + Required bool `json:"required"` + // for element types "input" + IsNumber bool `json:"is_number"` + // for element types "input" + Regex string `json:"regex"` +} + +// IssueFormElementType is an enum +type IssueFormElementType string + +const ( + // IssueFormElementMarkdown is markdown rendered to the form for context, but omitted in the resulting issue + IssueFormElementMarkdown IssueFormElementType = "markdown" + // IssueFormElementTextarea is a multi line input + IssueFormElementTextarea IssueFormElementType = "textarea" + // IssueFormElementInput is a single line input + IssueFormElementInput IssueFormElementType = "input" + // IssueFormElementDropdown is a select form + IssueFormElementDropdown IssueFormElementType = "dropdown" + // IssueFormElementCheckboxes are a multi checkbox input + IssueFormElementCheckboxes IssueFormElementType = "checkboxes" +) + +// GetIssueTemplates lists all issue templates of the repository +func (c *Client) GetIssueTemplates(owner, repo string) ([]*IssueTemplate, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } + templates := new([]*IssueTemplate) + resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issue_templates", owner, repo), nil, nil, templates) + return *templates, resp, err +} + +// IsForm tells if this template is a form instead of a markdown-based template. +func (t IssueTemplate) IsForm() bool { + return t.Form != nil +} diff --git a/vendor/code.gitea.io/sdk/gitea/list_options.go b/vendor/code.gitea.io/sdk/gitea/list_options.go index 6f3ffb2313c..fb1aff4e832 100644 --- a/vendor/code.gitea.io/sdk/gitea/list_options.go +++ b/vendor/code.gitea.io/sdk/gitea/list_options.go @@ -9,12 +9,13 @@ import ( "net/url" ) -const defaultPageSize = 10 -const maxPageSize = 50 - // ListOptions options for using Gitea's API pagination type ListOptions struct { - Page int + // Setting Page to -1 disables pagination on endpoints that support it. + // Page numbering starts at 1. + Page int + // The default value depends on the server config DEFAULT_PAGING_NUM + // The highest valid value depends on the server config MAX_RESPONSE_ITEMS PageSize int } @@ -26,8 +27,9 @@ func (o ListOptions) getURLQuery() url.Values { return query } -// setDefaults set default pagination options if none or wrong are set -// if you set -1 as page it will set all to 0 +// setDefaults applies default pagination options. +// If .Page is set to -1, it will disable pagination. +// WARNING: This function is not idempotent, make sure to never call this method twice! func (o *ListOptions) setDefaults() { if o.Page < 0 { o.Page, o.PageSize = 0, 0 @@ -35,8 +37,4 @@ func (o *ListOptions) setDefaults() { } else if o.Page == 0 { o.Page = 1 } - - if o.PageSize < 0 || o.PageSize > maxPageSize { - o.PageSize = defaultPageSize - } } diff --git a/vendor/code.gitea.io/sdk/gitea/notifications.go b/vendor/code.gitea.io/sdk/gitea/notifications.go index 8b1ffa7ba2b..640cc4daece 100644 --- a/vendor/code.gitea.io/sdk/gitea/notifications.go +++ b/vendor/code.gitea.io/sdk/gitea/notifications.go @@ -8,12 +8,6 @@ import ( "fmt" "net/url" "time" - - "github.com/hashicorp/go-version" -) - -var ( - version1_12_3, _ = version.NewVersion("1.12.3") ) // NotificationThread expose Notification on API @@ -29,11 +23,13 @@ type NotificationThread struct { // NotificationSubject contains the notification subject (Issue/Pull/Commit) type NotificationSubject struct { - Title string `json:"title"` - URL string `json:"url"` - LatestCommentURL string `json:"latest_comment_url"` - Type NotifySubjectType `json:"type"` - State NotifySubjectState `json:"state"` + Title string `json:"title"` + URL string `json:"url"` + HTMLURL string `json:"html_url"` + LatestCommentURL string `json:"latest_comment_url"` + LatestCommentHTMLURL string `json:"latest_comment_html_url"` + Type NotifySubjectType `json:"type"` + State NotifySubjectState `json:"state"` } // NotifyStatus notification status type @@ -164,16 +160,22 @@ func (c *Client) GetNotification(id int64) (*NotificationThread, *Response, erro // ReadNotification mark notification thread as read by ID // It optionally takes a second argument if status has to be set other than 'read' -func (c *Client) ReadNotification(id int64, status ...NotifyStatus) (*Response, error) { +// The relevant notification will be returned as the first parameter when the Gitea server is 1.16.0 or higher. +func (c *Client) ReadNotification(id int64, status ...NotifyStatus) (*NotificationThread, *Response, error) { if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { - return nil, err + return nil, nil, err } link := fmt.Sprintf("/notifications/threads/%d", id) if len(status) != 0 { link += fmt.Sprintf("?to-status=%s", status[0]) } + if err := c.checkServerVersionGreaterThanOrEqual(version1_16_0); err == nil { + thread := &NotificationThread{} + resp, err := c.getParsedResponse("PATCH", link, nil, nil, thread) + return thread, resp, err + } _, resp, err := c.getResponse("PATCH", link, nil, nil) - return resp, err + return nil, resp, err } // ListNotifications list users's notification threads @@ -192,17 +194,24 @@ func (c *Client) ListNotifications(opt ListNotificationOptions) ([]*Notification } // ReadNotifications mark notification threads as read -func (c *Client) ReadNotifications(opt MarkNotificationOptions) (*Response, error) { +// The relevant notifications will only be returned as the first parameter when the Gitea server is 1.16.0 or higher. +func (c *Client) ReadNotifications(opt MarkNotificationOptions) ([]*NotificationThread, *Response, error) { if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { - return nil, err + return nil, nil, err } if err := opt.Validate(c); err != nil { - return nil, err + return nil, nil, err } link, _ := url.Parse("/notifications") link.RawQuery = opt.QueryEncode() + + if err := c.checkServerVersionGreaterThanOrEqual(version1_16_0); err == nil { + threads := make([]*NotificationThread, 0, 10) + resp, err := c.getParsedResponse("PUT", link.String(), nil, nil, &threads) + return threads, resp, err + } _, resp, err := c.getResponse("PUT", link.String(), nil, nil) - return resp, err + return nil, resp, err } // ListRepoNotifications list users's notification threads on a specific repo @@ -224,18 +233,25 @@ func (c *Client) ListRepoNotifications(owner, repo string, opt ListNotificationO } // ReadRepoNotifications mark notification threads as read on a specific repo -func (c *Client) ReadRepoNotifications(owner, repo string, opt MarkNotificationOptions) (*Response, error) { +// The relevant notifications will only be returned as the first parameter when the Gitea server is 1.16.0 or higher. +func (c *Client) ReadRepoNotifications(owner, repo string, opt MarkNotificationOptions) ([]*NotificationThread, *Response, error) { if err := escapeValidatePathSegments(&owner, &repo); err != nil { - return nil, err + return nil, nil, err } if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { - return nil, err + return nil, nil, err } if err := opt.Validate(c); err != nil { - return nil, err + return nil, nil, err } link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, repo)) link.RawQuery = opt.QueryEncode() + + if err := c.checkServerVersionGreaterThanOrEqual(version1_16_0); err == nil { + threads := make([]*NotificationThread, 0, 10) + resp, err := c.getParsedResponse("PUT", link.String(), nil, nil, &threads) + return threads, resp, err + } _, resp, err := c.getResponse("PUT", link.String(), nil, nil) - return resp, err + return nil, resp, err } diff --git a/vendor/code.gitea.io/sdk/gitea/oauth2.go b/vendor/code.gitea.io/sdk/gitea/oauth2.go index bbdfdafb671..86e25683876 100644 --- a/vendor/code.gitea.io/sdk/gitea/oauth2.go +++ b/vendor/code.gitea.io/sdk/gitea/oauth2.go @@ -13,12 +13,13 @@ import ( // Oauth2 represents an Oauth2 Application type Oauth2 struct { - ID int64 `json:"id"` - Name string `json:"name"` - ClientID string `json:"client_id"` - ClientSecret string `json:"client_secret"` - RedirectURIs []string `json:"redirect_uris"` - Created time.Time `json:"created"` + ID int64 `json:"id"` + Name string `json:"name"` + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret"` + RedirectURIs []string `json:"redirect_uris"` + ConfidentialClient bool `json:"confidential_client"` + Created time.Time `json:"created"` } // ListOauth2Option for listing Oauth2 Applications @@ -28,8 +29,9 @@ type ListOauth2Option struct { // CreateOauth2Option required options for creating an Application type CreateOauth2Option struct { - Name string `json:"name"` - RedirectURIs []string `json:"redirect_uris"` + Name string `json:"name"` + ConfidentialClient bool `json:"confidential_client"` + RedirectURIs []string `json:"redirect_uris"` } // CreateOauth2 create an Oauth2 Application and returns a completed Oauth2 object. diff --git a/vendor/code.gitea.io/sdk/gitea/org_action.go b/vendor/code.gitea.io/sdk/gitea/org_action.go new file mode 100644 index 00000000000..a1dec286765 --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/org_action.go @@ -0,0 +1,29 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "fmt" + "net/url" +) + +// ListOrgMembershipOption list OrgMembership options +type ListOrgActionSecretOption struct { + ListOptions +} + +// ListOrgMembership list an organization's members +func (c *Client) ListOrgActionSecret(org string, opt ListOrgActionSecretOption) ([]*Secret, *Response, error) { + if err := escapeValidatePathSegments(&org); err != nil { + return nil, nil, err + } + opt.setDefaults() + secrets := make([]*Secret, 0, opt.PageSize) + + link, _ := url.Parse(fmt.Sprintf("/orgs/%s/actions/secrets", org)) + link.RawQuery = opt.getURLQuery().Encode() + resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &secrets) + return secrets, resp, err +} diff --git a/vendor/code.gitea.io/sdk/gitea/org_member.go b/vendor/code.gitea.io/sdk/gitea/org_member.go index 1eed90f6b65..79dad4e87c6 100644 --- a/vendor/code.gitea.io/sdk/gitea/org_member.go +++ b/vendor/code.gitea.io/sdk/gitea/org_member.go @@ -117,3 +117,26 @@ func (c *Client) SetPublicOrgMembership(org, user string, visible bool) (*Respon return resp, fmt.Errorf("unexpected Status: %d", status) } } + +// OrgPermissions represents the permissions for an user in an organization +type OrgPermissions struct { + CanCreateRepository bool `json:"can_create_repository"` + CanRead bool `json:"can_read"` + CanWrite bool `json:"can_write"` + IsAdmin bool `json:"is_admin"` + IsOwner bool `json:"is_owner"` +} + +// GetOrgPermissions returns user permissions for specific organization. +func (c *Client) GetOrgPermissions(org, user string) (*OrgPermissions, *Response, error) { + if err := escapeValidatePathSegments(&org, &user); err != nil { + return nil, nil, err + } + + perm := &OrgPermissions{} + resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/orgs/%s/permissions", user, org), jsonHeader, nil, &perm) + if err != nil { + return nil, resp, err + } + return perm, resp, nil +} diff --git a/vendor/code.gitea.io/sdk/gitea/org_team.go b/vendor/code.gitea.io/sdk/gitea/org_team.go index 4b1b27b4b71..e7caa5ae863 100644 --- a/vendor/code.gitea.io/sdk/gitea/org_team.go +++ b/vendor/code.gitea.io/sdk/gitea/org_team.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/json" "fmt" + "net/url" ) // Team represents a team in an organization @@ -42,6 +43,8 @@ const ( RepoUnitReleases RepoUnitType = "repo.releases" // RepoUnitProjects represent projects of a repository RepoUnitProjects RepoUnitType = "repo.projects" + // RepoUnitPackages represents packages of a repository + RepoUnitPackages RepoUnitType = "repo.packages" ) // ListTeamsOptions options for listing teams @@ -75,6 +78,44 @@ func (c *Client) GetTeam(id int64) (*Team, *Response, error) { return t, resp, err } +// SearchTeamsOptions options for searching teams. +type SearchTeamsOptions struct { + ListOptions + Query string + IncludeDescription bool +} + +func (o SearchTeamsOptions) getURLQuery() url.Values { + query := make(url.Values) + query.Add("page", fmt.Sprintf("%d", o.Page)) + query.Add("limit", fmt.Sprintf("%d", o.PageSize)) + query.Add("q", o.Query) + query.Add("include_desc", fmt.Sprintf("%t", o.IncludeDescription)) + + return query +} + +// TeamSearchResults is the JSON struct that is returned from Team search API. +type TeamSearchResults struct { + OK bool `json:"ok"` + Error string `json:"error"` + Data []*Team `json:"data"` +} + +// SearchOrgTeams search for teams in a org. +func (c *Client) SearchOrgTeams(org string, opt *SearchTeamsOptions) ([]*Team, *Response, error) { + responseBody := TeamSearchResults{} + opt.setDefaults() + resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/teams/search?%s", org, opt.getURLQuery().Encode()), nil, nil, &responseBody) + if err != nil { + return nil, resp, err + } + if !responseBody.OK { + return nil, resp, fmt.Errorf("gitea error: %v", responseBody.Error) + } + return responseBody.Data, resp, err +} + // CreateTeamOption options for creating a team type CreateTeamOption struct { Name string `json:"name"` @@ -86,7 +127,7 @@ type CreateTeamOption struct { } // Validate the CreateTeamOption struct -func (opt CreateTeamOption) Validate() error { +func (opt *CreateTeamOption) Validate() error { if opt.Permission == AccessModeOwner { opt.Permission = AccessModeAdmin } else if opt.Permission != AccessModeRead && opt.Permission != AccessModeWrite && opt.Permission != AccessModeAdmin { @@ -109,7 +150,7 @@ func (c *Client) CreateTeam(org string, opt CreateTeamOption) (*Team, *Response, if err := escapeValidatePathSegments(&org); err != nil { return nil, nil, err } - if err := opt.Validate(); err != nil { + if err := (&opt).Validate(); err != nil { return nil, nil, err } body, err := json.Marshal(&opt) @@ -132,7 +173,7 @@ type EditTeamOption struct { } // Validate the EditTeamOption struct -func (opt EditTeamOption) Validate() error { +func (opt *EditTeamOption) Validate() error { if opt.Permission == AccessModeOwner { opt.Permission = AccessModeAdmin } else if opt.Permission != AccessModeRead && opt.Permission != AccessModeWrite && opt.Permission != AccessModeAdmin { @@ -152,7 +193,7 @@ func (opt EditTeamOption) Validate() error { // EditTeam edits a team of an organization func (c *Client) EditTeam(id int64, opt EditTeamOption) (*Response, error) { - if err := opt.Validate(); err != nil { + if err := (&opt).Validate(); err != nil { return nil, err } body, err := json.Marshal(&opt) diff --git a/vendor/code.gitea.io/sdk/gitea/package.go b/vendor/code.gitea.io/sdk/gitea/package.go new file mode 100644 index 00000000000..df3bd3cf4dd --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/package.go @@ -0,0 +1,93 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "fmt" + "time" +) + +// Package represents a package +type Package struct { + // the package's id + ID int64 `json:"id"` + // the package's owner + Owner User `json:"owner"` + // the repo this package belongs to (if any) + Repository *string `json:"repository"` + // the package's creator + Creator User `json:"creator"` + // the type of package: + Type string `json:"type"` + // the name of the package + Name string `json:"name"` + // the version of the package + Version string `json:"version"` + // the date the package was uploaded + CreatedAt time.Time `json:"created_at"` +} + +// PackageFile represents a file from a package +type PackageFile struct { + // the file's ID + ID int64 `json:"id"` + // the size of the file in bytes + Size int64 `json:"size"` + // the name of the file + Name string `json:"name"` + // the md5 hash of the file + MD5 string `json:"md5"` + // the sha1 hash of the file + SHA1 string `json:"sha1"` + // the sha256 hash of the file + SHA256 string `json:"sha256"` + // the sha512 hash of the file + SHA512 string `json:"sha512"` +} + +// ListPackagesOptions options for listing packages +type ListPackagesOptions struct { + ListOptions +} + +// ListPackages lists all the packages owned by a given owner (user, organisation) +func (c *Client) ListPackages(owner string, opt ListPackagesOptions) ([]*Package, *Response, error) { + if err := escapeValidatePathSegments(&owner); err != nil { + return nil, nil, err + } + opt.setDefaults() + packages := make([]*Package, 0, opt.PageSize) + resp, err := c.getParsedResponse("GET", fmt.Sprintf("/packages/%s?%s", owner, opt.getURLQuery().Encode()), nil, nil, &packages) + return packages, resp, err +} + +// GetPackage gets the details of a specific package version +func (c *Client) GetPackage(owner, packageType, name, version string) (*Package, *Response, error) { + if err := escapeValidatePathSegments(&owner, &packageType, &name, &version); err != nil { + return nil, nil, err + } + foundPackage := new(Package) + resp, err := c.getParsedResponse("GET", fmt.Sprintf("/packages/%s/%s/%s/%s", owner, packageType, name, version), nil, nil, foundPackage) + return foundPackage, resp, err +} + +// DeletePackage deletes a specific package version +func (c *Client) DeletePackage(owner, packageType, name, version string) (*Response, error) { + if err := escapeValidatePathSegments(&owner, &packageType, &name, &version); err != nil { + return nil, err + } + _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/packages/%s/%s/%s/%s", owner, packageType, name, version), nil, nil) + return resp, err +} + +// ListPackageFiles lists the files within a package +func (c *Client) ListPackageFiles(owner, packageType, name, version string) ([]*PackageFile, *Response, error) { + if err := escapeValidatePathSegments(&owner, &packageType, &name, &version); err != nil { + return nil, nil, err + } + packageFiles := make([]*PackageFile, 0) + resp, err := c.getParsedResponse("GET", fmt.Sprintf("/packages/%s/%s/%s/%s/files", owner, packageType, name, version), nil, nil, &packageFiles) + return packageFiles, resp, err +} diff --git a/vendor/code.gitea.io/sdk/gitea/pull.go b/vendor/code.gitea.io/sdk/gitea/pull.go index e0198c28902..8ca81647222 100644 --- a/vendor/code.gitea.io/sdk/gitea/pull.go +++ b/vendor/code.gitea.io/sdk/gitea/pull.go @@ -12,8 +12,6 @@ import ( "net/url" "strings" "time" - - "github.com/hashicorp/go-version" ) // PRBranchInfo information about a branch @@ -45,11 +43,12 @@ type PullRequest struct { DiffURL string `json:"diff_url"` PatchURL string `json:"patch_url"` - Mergeable bool `json:"mergeable"` - HasMerged bool `json:"merged"` - Merged *time.Time `json:"merged_at"` - MergedCommitID *string `json:"merge_commit_sha"` - MergedBy *User `json:"merged_by"` + Mergeable bool `json:"mergeable"` + HasMerged bool `json:"merged"` + Merged *time.Time `json:"merged_at"` + MergedCommitID *string `json:"merge_commit_sha"` + MergedBy *User `json:"merged_by"` + AllowMaintainerEdit bool `json:"allow_maintainer_edit"` Base *PRBranchInfo `json:"base"` Head *PRBranchInfo `json:"head"` @@ -61,6 +60,19 @@ type PullRequest struct { Closed *time.Time `json:"closed_at"` } +// ChangedFile is a changed file in a diff +type ChangedFile struct { + Filename string `json:"filename"` + PreviousFilename string `json:"previous_filename"` + Status string `json:"status"` + Additions int `json:"additions"` + Deletions int `json:"deletions"` + Changes int `json:"changes"` + HTMLURL string `json:"html_url"` + ContentsURL string `json:"contents_url"` + RawURL string `json:"raw_url"` +} + // ListPullRequestsOptions options for listing pull requests type ListPullRequestsOptions struct { ListOptions @@ -166,15 +178,17 @@ func (c *Client) CreatePullRequest(owner, repo string, opt CreatePullRequestOpti // EditPullRequestOption options when modify pull request type EditPullRequestOption struct { - Title string `json:"title"` - Body string `json:"body"` - Base string `json:"base"` - Assignee string `json:"assignee"` - Assignees []string `json:"assignees"` - Milestone int64 `json:"milestone"` - Labels []int64 `json:"labels"` - State *StateType `json:"state"` - Deadline *time.Time `json:"due_date"` + Title string `json:"title"` + Body string `json:"body"` + Base string `json:"base"` + Assignee string `json:"assignee"` + Assignees []string `json:"assignees"` + Milestone int64 `json:"milestone"` + Labels []int64 `json:"labels"` + State *StateType `json:"state"` + Deadline *time.Time `json:"due_date"` + RemoveDeadline *bool `json:"unset_due_date"` + AllowMaintainerEdit *bool `json:"allow_maintainer_edit"` } // Validate the EditPullRequestOption struct @@ -211,13 +225,16 @@ func (c *Client) EditPullRequest(owner, repo string, index int64, opt EditPullRe // MergePullRequestOption options when merging a pull request type MergePullRequestOption struct { - Style MergeStyle `json:"Do"` - Title string `json:"MergeTitleField"` - Message string `json:"MergeMessageField"` + Style MergeStyle `json:"Do"` + MergeCommitID string `json:"MergeCommitID"` + Title string `json:"MergeTitleField"` + Message string `json:"MergeMessageField"` + DeleteBranchAfterMerge bool `json:"delete_branch_after_merge"` + ForceMerge bool `json:"force_merge"` + HeadCommitId string `json:"head_commit_id"` + MergeWhenChecksSucceed bool `json:"merge_when_checks_succeed"` } -var version1_11_5, _ = version.NewVersion("1.11.5") - // Validate the MergePullRequestOption struct func (opt MergePullRequestOption) Validate(c *Client) error { if opt.Style == MergeStyleSquash { @@ -253,7 +270,6 @@ func (c *Client) IsPullRequestMerged(owner, repo string, index int64) (bool, *Re 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 { return false, resp, err } @@ -261,9 +277,29 @@ func (c *Client) IsPullRequestMerged(owner, repo string, index int64) (bool, *Re return status == 204, resp, nil } +// PullRequestDiffOptions options for GET /repos///pulls/.[diff|patch] +type PullRequestDiffOptions struct { + // Include binary file changes when requesting a .diff + Binary bool +} + +// QueryEncode converts the options to a query string +func (o PullRequestDiffOptions) QueryEncode() string { + query := make(url.Values) + query.Add("binary", fmt.Sprintf("%v", o.Binary)) + return query.Encode() +} + +type pullRequestDiffType string + +const ( + pullRequestDiffTypeDiff pullRequestDiffType = "diff" + pullRequestDiffTypePatch pullRequestDiffType = "patch" +) + // 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 { +func (c *Client) getPullRequestDiffOrPatch(owner, repo string, kind pullRequestDiffType, index int64, opts PullRequestDiffOptions) ([]byte, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { return nil, nil, err } if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { @@ -274,19 +310,20 @@ func (c *Client) getPullRequestDiffOrPatch(owner, repo, kind string, index int64 if r.Private { return nil, nil, err } - return c.getWebResponse("GET", fmt.Sprintf("/%s/%s/pulls/%d.%s", owner, repo, index, kind), nil) + url := fmt.Sprintf("/%s/%s/pulls/%d.%s?%s", owner, repo, index, kind, opts.QueryEncode()) + return c.getWebResponse("GET", url, nil) } return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d.%s", owner, repo, index, kind), nil, nil) } -// GetPullRequestPatch gets the .patch file as bytes for a PR +// GetPullRequestPatch gets the git patchset of a PR func (c *Client) GetPullRequestPatch(owner, repo string, index int64) ([]byte, *Response, error) { - return c.getPullRequestDiffOrPatch(owner, repo, "patch", index) + return c.getPullRequestDiffOrPatch(owner, repo, pullRequestDiffTypePatch, index, PullRequestDiffOptions{}) } -// GetPullRequestDiff gets the .diff file as bytes for a PR -func (c *Client) GetPullRequestDiff(owner, repo string, index int64) ([]byte, *Response, error) { - return c.getPullRequestDiffOrPatch(owner, repo, "diff", index) +// GetPullRequestDiff gets the diff of a PR. For Gitea >= 1.16, you must set includeBinary to get an applicable diff +func (c *Client) GetPullRequestDiff(owner, repo string, index int64, opts PullRequestDiffOptions) ([]byte, *Response, error) { + return c.getPullRequestDiffOrPatch(owner, repo, pullRequestDiffTypeDiff, index, opts) } // ListPullRequestCommitsOptions options for listing pull requests @@ -326,3 +363,21 @@ func fixPullHeadSha(client *Client, pr *PullRequest) error { } return nil } + +// ListPullRequestFilesOptions options for listing pull request files +type ListPullRequestFilesOptions struct { + ListOptions +} + +// ListPullRequestFiles list changed files for a pull request +func (c *Client) ListPullRequestFiles(owner, repo string, index int64, opt ListPullRequestFilesOptions) ([]*ChangedFile, *Response, error) { + if err := escapeValidatePathSegments(&owner, &repo); err != nil { + return nil, nil, err + } + link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls/%d/files", owner, repo, index)) + opt.setDefaults() + files := make([]*ChangedFile, 0, opt.PageSize) + link.RawQuery = opt.getURLQuery().Encode() + resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &files) + return files, resp, err +} diff --git a/vendor/code.gitea.io/sdk/gitea/pull_review.go b/vendor/code.gitea.io/sdk/gitea/pull_review.go index a484dfdd9c0..6d32c4f1246 100644 --- a/vendor/code.gitea.io/sdk/gitea/pull_review.go +++ b/vendor/code.gitea.io/sdk/gitea/pull_review.go @@ -116,7 +116,7 @@ type ListPullReviewsOptions struct { // Validate the CreatePullReviewOptions struct func (opt CreatePullReviewOptions) Validate() error { - if opt.State != ReviewStateApproved && len(strings.TrimSpace(opt.Body)) == 0 { + if opt.State != ReviewStateApproved && len(opt.Comments) == 0 && len(strings.TrimSpace(opt.Body)) == 0 { return fmt.Errorf("body is empty") } for i := range opt.Comments { diff --git a/vendor/code.gitea.io/sdk/gitea/release.go b/vendor/code.gitea.io/sdk/gitea/release.go index c8e7681d02c..3200f203430 100644 --- a/vendor/code.gitea.io/sdk/gitea/release.go +++ b/vendor/code.gitea.io/sdk/gitea/release.go @@ -47,7 +47,7 @@ func (opt *ListReleasesOptions) QueryEncode() string { query.Add("draft", fmt.Sprintf("%t", *opt.IsDraft)) } if opt.IsPreRelease != nil { - query.Add("draft", fmt.Sprintf("%t", *opt.IsPreRelease)) + query.Add("pre-release", fmt.Sprintf("%t", *opt.IsPreRelease)) } return query.Encode() @@ -79,7 +79,7 @@ func (c *Client) GetRelease(owner, repo string, id int64) (*Release, *Response, } // GetReleaseByTag get a release of a repository by tag -func (c *Client) GetReleaseByTag(owner, repo string, tag string) (*Release, *Response, error) { +func (c *Client) GetReleaseByTag(owner, repo, tag string) (*Release, *Response, error) { if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { return c.fallbackGetReleaseByTag(owner, repo, tag) } @@ -168,7 +168,7 @@ 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) { +func (c *Client) DeleteReleaseByTag(user, repo, tag string) (*Response, error) { if err := escapeValidatePathSegments(&user, &repo, &tag); err != nil { return nil, err } @@ -182,7 +182,7 @@ 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(owner, repo string, tag string) (*Release, *Response, error) { +func (c *Client) fallbackGetReleaseByTag(owner, repo, tag string) (*Release, *Response, error) { for i := 1; ; i++ { rl, resp, err := c.ListReleases(owner, repo, ListReleasesOptions{ListOptions: ListOptions{Page: i}}) if err != nil { diff --git a/vendor/code.gitea.io/sdk/gitea/repo.go b/vendor/code.gitea.io/sdk/gitea/repo.go index 62d13a3ab57..8f0e346abef 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo.go +++ b/vendor/code.gitea.io/sdk/gitea/repo.go @@ -93,6 +93,7 @@ type Repository struct { AvatarURL string `json:"avatar_url"` Internal bool `json:"internal"` MirrorInterval string `json:"mirror_interval"` + MirrorUpdated time.Time `json:"mirror_updated,omitempty"` DefaultMergeStyle MergeStyle `json:"default_merge_style"` } @@ -286,7 +287,9 @@ func (c *Client) SearchRepos(opt SearchRepoOptions) ([]*Repository, *Response, e // private repos only not supported on gitea <= 1.11.x return nil, nil, err } - link.Query().Add("private", "false") + newQuery := link.Query() + newQuery.Add("private", "false") + link.RawQuery = newQuery.Encode() } } @@ -329,10 +332,10 @@ func (opt CreateRepoOption) Validate(c *Client) error { return fmt.Errorf("name has more than 100 chars") } if len(opt.Description) > 255 { - return fmt.Errorf("name has more than 255 chars") + return fmt.Errorf("description has more than 255 chars") } if len(opt.DefaultBranch) > 100 { - return fmt.Errorf("name has more than 100 chars") + return fmt.Errorf("default branch name has more than 100 chars") } if len(opt.TrustModel) != 0 { if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { diff --git a/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go b/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go index 22bd7b96295..3196d03bfd0 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go @@ -15,6 +15,7 @@ import ( // BranchProtection represents a branch protection for a repository type BranchProtection struct { BranchName string `json:"branch_name"` + RuleName string `json:"rule_name"` EnablePush bool `json:"enable_push"` EnablePushWhitelist bool `json:"enable_push_whitelist"` PushWhitelistUsernames []string `json:"push_whitelist_usernames"` @@ -35,6 +36,7 @@ type BranchProtection struct { DismissStaleApprovals bool `json:"dismiss_stale_approvals"` RequireSignedCommits bool `json:"require_signed_commits"` ProtectedFilePatterns string `json:"protected_file_patterns"` + UnprotectedFilePatterns string `json:"unprotected_file_patterns"` Created time.Time `json:"created_at"` Updated time.Time `json:"updated_at"` } @@ -42,6 +44,7 @@ type BranchProtection struct { // CreateBranchProtectionOption options for creating a branch protection type CreateBranchProtectionOption struct { BranchName string `json:"branch_name"` + RuleName string `json:"rule_name"` EnablePush bool `json:"enable_push"` EnablePushWhitelist bool `json:"enable_push_whitelist"` PushWhitelistUsernames []string `json:"push_whitelist_usernames"` @@ -62,6 +65,7 @@ type CreateBranchProtectionOption struct { DismissStaleApprovals bool `json:"dismiss_stale_approvals"` RequireSignedCommits bool `json:"require_signed_commits"` ProtectedFilePatterns string `json:"protected_file_patterns"` + UnprotectedFilePatterns string `json:"unprotected_file_patterns"` } // EditBranchProtectionOption options for editing a branch protection @@ -86,6 +90,7 @@ type EditBranchProtectionOption struct { DismissStaleApprovals *bool `json:"dismiss_stale_approvals"` RequireSignedCommits *bool `json:"require_signed_commits"` ProtectedFilePatterns *string `json:"protected_file_patterns"` + UnprotectedFilePatterns *string `json:"unprotected_file_patterns"` } // ListBranchProtectionsOptions list branch protection options diff --git a/vendor/code.gitea.io/sdk/gitea/repo_collaborator.go b/vendor/code.gitea.io/sdk/gitea/repo_collaborator.go index c766250f429..41e25765505 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_collaborator.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_collaborator.go @@ -16,6 +16,13 @@ type ListCollaboratorsOptions struct { ListOptions } +// CollaboratorPermissionResult result type for CollaboratorPermission +type CollaboratorPermissionResult struct { + Permission AccessMode `json:"permission"` + Role string `json:"role_name"` + User *User `json:"user"` +} + // 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 { @@ -44,6 +51,26 @@ func (c *Client) IsCollaborator(user, repo, collaborator string) (bool, *Respons return false, resp, nil } +// CollaboratorPermission gets collaborator permission of a repository +func (c *Client) CollaboratorPermission(user, repo, collaborator string) (*CollaboratorPermissionResult, *Response, error) { + if err := escapeValidatePathSegments(&user, &repo, &collaborator); err != nil { + return nil, nil, err + } + rv := new(CollaboratorPermissionResult) + resp, err := c.getParsedResponse("GET", + fmt.Sprintf("/repos/%s/%s/collaborators/%s/permission", user, repo, collaborator), + nil, + nil, + rv) + if err != nil { + return nil, resp, err + } + if resp.StatusCode != 200 { + rv = nil + } + return rv, resp, nil +} + // AddCollaboratorOption options when adding a user as a collaborator of a repository type AddCollaboratorOption struct { Permission *AccessMode `json:"permission"` @@ -66,7 +93,7 @@ const ( ) // Validate the AddCollaboratorOption struct -func (opt AddCollaboratorOption) Validate() error { +func (opt *AddCollaboratorOption) Validate() error { if opt.Permission != nil { if *opt.Permission == AccessModeOwner { *opt.Permission = AccessModeAdmin @@ -88,7 +115,7 @@ func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollabo if err := escapeValidatePathSegments(&user, &repo, &collaborator); err != nil { return nil, err } - if err := opt.Validate(); err != nil { + if err := (&opt).Validate(); err != nil { return nil, err } body, err := json.Marshal(&opt) diff --git a/vendor/code.gitea.io/sdk/gitea/repo_commit.go b/vendor/code.gitea.io/sdk/gitea/repo_commit.go index 9bb65b3b11e..62c0ab31c74 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_commit.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_commit.go @@ -32,11 +32,19 @@ type CommitUser struct { // RepoCommit contains information of a commit in the context of a repository. type RepoCommit struct { - URL string `json:"url"` - Author *CommitUser `json:"author"` - Committer *CommitUser `json:"committer"` - Message string `json:"message"` - Tree *CommitMeta `json:"tree"` + URL string `json:"url"` + Author *CommitUser `json:"author"` + Committer *CommitUser `json:"committer"` + Message string `json:"message"` + Tree *CommitMeta `json:"tree"` + Verification *PayloadCommitVerification `json:"verification"` +} + +// CommitStats contains stats from a Git commit +type CommitStats struct { + Total int `json:"total"` + Additions int `json:"additions"` + Deletions int `json:"deletions"` } // Commit contains information generated from a Git commit. @@ -48,6 +56,7 @@ type Commit struct { Committer *User `json:"committer"` Parents []*CommitMeta `json:"parents"` Files []*CommitAffectedFiles `json:"files"` + Stats *CommitStats `json:"stats"` } // CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE @@ -74,16 +83,21 @@ func (c *Client) GetSingleCommit(user, repo, commitID string) (*Commit, *Respons // ListCommitOptions list commit options type ListCommitOptions struct { ListOptions - //SHA or branch to start listing commits from (usually 'master') + // SHA or branch to start listing commits from (usually 'master') SHA string + // Path indicates that only commits that include the path's file/dir should be returned. + Path string } // QueryEncode turns options into querystring argument func (opt *ListCommitOptions) QueryEncode() string { - query := opt.ListOptions.getURLQuery() + query := opt.getURLQuery() if opt.SHA != "" { query.Add("sha", opt.SHA) } + if opt.Path != "" { + query.Add("path", opt.Path) + } return query.Encode() } @@ -99,3 +113,29 @@ func (c *Client) ListRepoCommits(user, repo string, opt ListCommitOptions) ([]*C resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &commits) return commits, resp, err } + +// GetCommitDiff returns the commit's raw diff. +func (c *Client) GetCommitDiff(user, repo, commitID string) ([]byte, *Response, error) { + if err := c.checkServerVersionGreaterThanOrEqual(version1_16_0); err != nil { + return nil, nil, err + } + + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } + + return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/git/commits/%s.%s", user, repo, commitID, pullRequestDiffTypeDiff), nil, nil) +} + +// GetCommitPatch returns the commit's raw patch. +func (c *Client) GetCommitPatch(user, repo, commitID string) ([]byte, *Response, error) { + if err := c.checkServerVersionGreaterThanOrEqual(version1_16_0); err != nil { + return nil, nil, err + } + + if err := escapeValidatePathSegments(&user, &repo); err != nil { + return nil, nil, err + } + + return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/git/commits/%s.%s", user, repo, commitID, pullRequestDiffTypePatch), nil, nil) +} diff --git a/vendor/code.gitea.io/sdk/gitea/repo_file.go b/vendor/code.gitea.io/sdk/gitea/repo_file.go index 6f99ea06bfb..bcba705129c 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_file.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_file.go @@ -9,6 +9,8 @@ import ( "bytes" "encoding/json" "fmt" + "io" + "io/ioutil" "net/url" "strings" ) @@ -117,17 +119,46 @@ type FileDeleteResponse struct { } // GetFile downloads a file of repository, ref can be branch/tag/commit. +// it optional can resolve lfs pointers and server the file instead // e.g.: ref -> master, filepath -> README.md (no leading slash) -func (c *Client) GetFile(owner, repo, ref, filepath string) ([]byte, *Response, error) { +func (c *Client) GetFile(owner, repo, ref, filepath string, resolveLFS ...bool) ([]byte, *Response, error) { + reader, resp, err := c.GetFileReader(owner, repo, ref, filepath, resolveLFS...) + if reader == nil { + return nil, resp, err + } + defer reader.Close() + + data, err2 := ioutil.ReadAll(reader) + if err2 != nil { + return nil, resp, err2 + } + + return data, resp, err +} + +// GetFileReader return reader for download a file of repository, ref can be branch/tag/commit. +// it optional can resolve lfs pointers and server the file instead +// e.g.: ref -> master, filepath -> README.md (no leading slash) +func (c *Client) GetFileReader(owner, repo, ref, filepath string, resolveLFS ...bool) (io.ReadCloser, *Response, error) { if err := escapeValidatePathSegments(&owner, &repo); err != nil { return nil, nil, err } + + // resolve lfs + if len(resolveLFS) != 0 && resolveLFS[0] { + if err := c.checkServerVersionGreaterThanOrEqual(version1_17_0); err != nil { + return nil, nil, err + } + return c.getResponseReader("GET", fmt.Sprintf("/repos/%s/%s/media/%s?ref=%s", owner, repo, filepath, url.QueryEscape(ref)), nil, nil) + } + + // normal get filepath = pathEscapeSegments(filepath) if c.checkServerVersionGreaterThanOrEqual(version1_14_0) != nil { ref = pathEscapeSegments(ref) - return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/raw/%s/%s", owner, repo, ref, filepath), nil, nil) + return c.getResponseReader("GET", fmt.Sprintf("/repos/%s/%s/raw/%s/%s", owner, repo, ref, filepath), nil, nil) } - return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/raw/%s?ref=%s", owner, repo, filepath, url.QueryEscape(ref)), nil, nil) + return c.getResponseReader("GET", fmt.Sprintf("/repos/%s/%s/raw/%s?ref=%s", owner, repo, filepath, url.QueryEscape(ref)), nil, nil) } // GetContents get the metadata and contents of a file in a repository diff --git a/vendor/code.gitea.io/sdk/gitea/repo_migrate.go b/vendor/code.gitea.io/sdk/gitea/repo_migrate.go index cd0fe44c80f..3ab690e53e0 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_migrate.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_migrate.go @@ -16,7 +16,7 @@ type GitServiceType string const ( // GitServicePlain represents a plain git service GitServicePlain GitServiceType = "git" - //GitServiceGithub represents github.com + // GitServiceGithub represents github.com GitServiceGithub GitServiceType = "github" // GitServiceGitlab represents a gitlab service GitServiceGitlab GitServiceType = "gitlab" diff --git a/vendor/code.gitea.io/sdk/gitea/repo_transfer.go b/vendor/code.gitea.io/sdk/gitea/repo_transfer.go index be06010a785..534a6e42c8a 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_transfer.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_transfer.go @@ -34,3 +34,29 @@ func (c *Client) TransferRepo(owner, reponame string, opt TransferRepoOption) (* resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/transfer", owner, reponame), jsonHeader, bytes.NewReader(body), repo) return repo, resp, err } + +// AcceptRepoTransfer accepts a repo transfer. +func (c *Client) AcceptRepoTransfer(owner, reponame string) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&owner, &reponame); err != nil { + return nil, nil, err + } + if err := c.checkServerVersionGreaterThanOrEqual(version1_16_0); err != nil { + return nil, nil, err + } + repo := new(Repository) + resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/transfer/accept", owner, reponame), jsonHeader, nil, repo) + return repo, resp, err +} + +// RejectRepoTransfer rejects a repo transfer. +func (c *Client) RejectRepoTransfer(owner, reponame string) (*Repository, *Response, error) { + if err := escapeValidatePathSegments(&owner, &reponame); err != nil { + return nil, nil, err + } + if err := c.checkServerVersionGreaterThanOrEqual(version1_16_0); err != nil { + return nil, nil, err + } + repo := new(Repository) + resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/transfer/reject", owner, reponame), jsonHeader, nil, repo) + return repo, resp, err +} diff --git a/vendor/code.gitea.io/sdk/gitea/repo_tree.go b/vendor/code.gitea.io/sdk/gitea/repo_tree.go index 452394a3c8f..c9ffc55e30b 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_tree.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_tree.go @@ -35,7 +35,7 @@ func (c *Client) GetTrees(user, repo, ref string, recursive bool) (*GitTreeRespo return nil, nil, err } trees := new(GitTreeResponse) - var path = fmt.Sprintf("/repos/%s/%s/git/trees/%s", user, repo, ref) + path := fmt.Sprintf("/repos/%s/%s/git/trees/%s", user, repo, ref) if recursive { path += "?recursive=1" } diff --git a/vendor/code.gitea.io/sdk/gitea/repo_watch.go b/vendor/code.gitea.io/sdk/gitea/repo_watch.go index f499aff2218..c36ca6403d9 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_watch.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_watch.go @@ -33,7 +33,7 @@ func (c *Client) GetWatchedRepos(user string) ([]*Repository, *Response, error) // GetMyWatchedRepos list repositories watched by the authenticated user func (c *Client) GetMyWatchedRepos() ([]*Repository, *Response, error) { repos := make([]*Repository, 0, 10) - resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/subscriptions"), nil, nil, &repos) + resp, err := c.getParsedResponse("GET", "/user/subscriptions", nil, nil, &repos) return repos, resp, err } diff --git a/vendor/code.gitea.io/sdk/gitea/secret.go b/vendor/code.gitea.io/sdk/gitea/secret.go new file mode 100644 index 00000000000..0f544a8c92e --- /dev/null +++ b/vendor/code.gitea.io/sdk/gitea/secret.go @@ -0,0 +1,14 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import "time" + +type Secret struct { + // the secret's name + Name string `json:"name"` + // Date and Time of secret creation + Created time.Time `json:"created_at"` +} diff --git a/vendor/code.gitea.io/sdk/gitea/user.go b/vendor/code.gitea.io/sdk/gitea/user.go index c37627bfaaa..67208fb0638 100644 --- a/vendor/code.gitea.io/sdk/gitea/user.go +++ b/vendor/code.gitea.io/sdk/gitea/user.go @@ -77,7 +77,6 @@ func (c *Client) GetUserByID(id int64) (*User, *Response, error) { query := make(url.Values) query.Add("uid", strconv.FormatInt(id, 10)) users, resp, err := c.searchUsers(query.Encode()) - if err != nil { return nil, resp, err } diff --git a/vendor/code.gitea.io/sdk/gitea/user_app.go b/vendor/code.gitea.io/sdk/gitea/user_app.go index 88b01ed083b..92a3a2601aa 100644 --- a/vendor/code.gitea.io/sdk/gitea/user_app.go +++ b/vendor/code.gitea.io/sdk/gitea/user_app.go @@ -13,12 +13,64 @@ import ( "reflect" ) +// AccessTokenScope represents the scope for an access token. +type AccessTokenScope string + +const ( + AccessTokenScopeAll AccessTokenScope = "all" + + AccessTokenScopeRepo AccessTokenScope = "repo" + AccessTokenScopeRepoStatus AccessTokenScope = "repo:status" + AccessTokenScopePublicRepo AccessTokenScope = "public_repo" + + AccessTokenScopeAdminOrg AccessTokenScope = "admin:org" + AccessTokenScopeWriteOrg AccessTokenScope = "write:org" + AccessTokenScopeReadOrg AccessTokenScope = "read:org" + + AccessTokenScopeAdminPublicKey AccessTokenScope = "admin:public_key" + AccessTokenScopeWritePublicKey AccessTokenScope = "write:public_key" + AccessTokenScopeReadPublicKey AccessTokenScope = "read:public_key" + + AccessTokenScopeAdminRepoHook AccessTokenScope = "admin:repo_hook" + AccessTokenScopeWriteRepoHook AccessTokenScope = "write:repo_hook" + AccessTokenScopeReadRepoHook AccessTokenScope = "read:repo_hook" + + AccessTokenScopeAdminOrgHook AccessTokenScope = "admin:org_hook" + + AccessTokenScopeAdminUserHook AccessTokenScope = "admin:user_hook" + + AccessTokenScopeNotification AccessTokenScope = "notification" + + AccessTokenScopeUser AccessTokenScope = "user" + AccessTokenScopeReadUser AccessTokenScope = "read:user" + AccessTokenScopeUserEmail AccessTokenScope = "user:email" + AccessTokenScopeUserFollow AccessTokenScope = "user:follow" + + AccessTokenScopeDeleteRepo AccessTokenScope = "delete_repo" + + AccessTokenScopePackage AccessTokenScope = "package" + AccessTokenScopeWritePackage AccessTokenScope = "write:package" + AccessTokenScopeReadPackage AccessTokenScope = "read:package" + AccessTokenScopeDeletePackage AccessTokenScope = "delete:package" + + AccessTokenScopeAdminGPGKey AccessTokenScope = "admin:gpg_key" + AccessTokenScopeWriteGPGKey AccessTokenScope = "write:gpg_key" + AccessTokenScopeReadGPGKey AccessTokenScope = "read:gpg_key" + + AccessTokenScopeAdminApplication AccessTokenScope = "admin:application" + AccessTokenScopeWriteApplication AccessTokenScope = "write:application" + AccessTokenScopeReadApplication AccessTokenScope = "read:application" + + AccessTokenScopeSudo AccessTokenScope = "sudo" +) + // AccessToken represents an API access token. type AccessToken struct { - ID int64 `json:"id"` - Name string `json:"name"` - Token string `json:"sha1"` - TokenLastEight string `json:"token_last_eight"` + ID int64 `json:"id"` + Name string `json:"name"` + Token string `json:"sha1"` + TokenLastEight string `json:"token_last_eight"` + Scopes []AccessTokenScope `json:"scopes"` } // ListAccessTokensOptions options for listing a users's access tokens @@ -42,7 +94,8 @@ func (c *Client) ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, // CreateAccessTokenOption options when create access token type CreateAccessTokenOption struct { - Name string `json:"name"` + Name string `json:"name"` + Scopes []AccessTokenScope `json:"scopes"` } // CreateAccessToken create one access token with options @@ -71,7 +124,7 @@ func (c *Client) DeleteAccessToken(value interface{}) (*Response, error) { return nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed") } - var token = "" + token := "" switch reflect.ValueOf(value).Kind() { case reflect.Int64: diff --git a/vendor/code.gitea.io/sdk/gitea/version.go b/vendor/code.gitea.io/sdk/gitea/version.go index 1f41c771835..e8df5119770 100644 --- a/vendor/code.gitea.io/sdk/gitea/version.go +++ b/vendor/code.gitea.io/sdk/gitea/version.go @@ -6,13 +6,14 @@ package gitea import ( "fmt" + "strings" "github.com/hashicorp/go-version" ) // ServerVersion returns the version of the server func (c *Client) ServerVersion() (string, *Response, error) { - var v = struct { + v := struct { Version string `json:"version"` }{} resp, err := c.getParsedResponse("GET", "/version", nil, nil, &v) @@ -52,7 +53,6 @@ func SetGiteaVersion(v string) ClientOption { return func(c *Client) (err error) { c.getVersionOnce.Do(func() { c.serverVersion, err = version.NewVersion(v) - return }) return } @@ -60,13 +60,33 @@ func SetGiteaVersion(v string) ClientOption { // predefined versions only have to be parsed by library once var ( - version1_11_0, _ = version.NewVersion("1.11.0") - version1_12_0, _ = version.NewVersion("1.12.0") - version1_13_0, _ = version.NewVersion("1.13.0") - version1_14_0, _ = version.NewVersion("1.14.0") - version1_15_0, _ = version.NewVersion("1.15.0") + version1_11_0 = version.Must(version.NewVersion("1.11.0")) + version1_11_5 = version.Must(version.NewVersion("1.11.5")) + version1_12_0 = version.Must(version.NewVersion("1.12.0")) + version1_12_3 = version.Must(version.NewVersion("1.12.3")) + version1_13_0 = version.Must(version.NewVersion("1.13.0")) + version1_14_0 = version.Must(version.NewVersion("1.14.0")) + version1_15_0 = version.Must(version.NewVersion("1.15.0")) + version1_16_0 = version.Must(version.NewVersion("1.16.0")) + version1_17_0 = version.Must(version.NewVersion("1.17.0")) ) +// ErrUnknownVersion is an unknown version from the API +type ErrUnknownVersion struct { + raw string +} + +// Error fulfills error +func (e ErrUnknownVersion) Error() string { + return fmt.Sprintf("unknown version: %s", e.raw) +} + +func (_ ErrUnknownVersion) Is(target error) bool { + _, ok1 := target.(*ErrUnknownVersion) + _, ok2 := target.(ErrUnknownVersion) + return ok1 || ok2 +} + // checkServerVersionGreaterThanOrEqual is the canonical way in the SDK to check for versions for API compatibility reasons func (c *Client) checkServerVersionGreaterThanOrEqual(v *version.Version) error { if c.ignoreVersion { @@ -94,6 +114,11 @@ func (c *Client) loadServerVersion() (err error) { return } if c.serverVersion, err = version.NewVersion(raw); err != nil { + if strings.TrimSpace(raw) != "" { + // Version was something, just not recognized + c.serverVersion = version1_11_0 + err = &ErrUnknownVersion{raw: raw} + } return } }) diff --git a/vendor/github.com/davidmz/go-pageant/LICENSE.txt b/vendor/github.com/davidmz/go-pageant/LICENSE.txt new file mode 100644 index 00000000000..bbe93b8c7dc --- /dev/null +++ b/vendor/github.com/davidmz/go-pageant/LICENSE.txt @@ -0,0 +1,16 @@ +Copyright (c) 2014 David Mzareulyan + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/davidmz/go-pageant/README.md b/vendor/github.com/davidmz/go-pageant/README.md new file mode 100644 index 00000000000..23a352e41a0 --- /dev/null +++ b/vendor/github.com/davidmz/go-pageant/README.md @@ -0,0 +1,9 @@ +[![GoDoc](https://godoc.org/github.com/davidmz/go-pageant?status.svg)](https://godoc.org/github.com/davidmz/go-pageant) + +Package pageant provides an interface to PyTTY pageant.exe utility. + +This package is windows-only. + +See documentation on [GoDoc](http://godoc.org/github.com/davidmz/go-pageant) + +License: MIT \ No newline at end of file diff --git a/vendor/github.com/davidmz/go-pageant/io_windows.go b/vendor/github.com/davidmz/go-pageant/io_windows.go new file mode 100644 index 00000000000..8f375515dc6 --- /dev/null +++ b/vendor/github.com/davidmz/go-pageant/io_windows.go @@ -0,0 +1,42 @@ +package pageant + +import ( + "io" + "sync" + + "golang.org/x/crypto/ssh/agent" +) + +// New returns new ssh-agent instance (see http://golang.org/x/crypto/ssh/agent) +func New() agent.Agent { + return agent.NewClient(&conn{}) +} + +type conn struct { + sync.Mutex + buf []byte +} + +func (c *conn) Write(p []byte) (int, error) { + c.Lock() + defer c.Unlock() + + resp, err := query(p) + if err != nil { + return 0, err + } + c.buf = append(c.buf, resp...) + return len(p), nil +} + +func (c *conn) Read(p []byte) (int, error) { + c.Lock() + defer c.Unlock() + + if len(c.buf) == 0 { + return 0, io.EOF + } + n := copy(p, c.buf) + c.buf = c.buf[n:] + return n, nil +} diff --git a/vendor/github.com/davidmz/go-pageant/pageant_windows.go b/vendor/github.com/davidmz/go-pageant/pageant_windows.go new file mode 100644 index 00000000000..520e8f4306f --- /dev/null +++ b/vendor/github.com/davidmz/go-pageant/pageant_windows.go @@ -0,0 +1,134 @@ +// Package pageant provides an interface to PyTTY pageant.exe utility. +// This package is windows-only +package pageant + +// see https://github.com/Yasushi/putty/blob/master/windows/winpgntc.c#L155 +// see https://github.com/paramiko/paramiko/blob/master/paramiko/win_pageant.py + +import ( + "encoding/binary" + "errors" + "fmt" + "sync" + "syscall" + "unsafe" +) + +// MaxMessageLen defines maximum size of message can be sent to pageant +const MaxMessageLen = 8192 + +var ( + // ErrPageantNotFound returns when pageant process not found + ErrPageantNotFound = errors.New("pageant process not found") + // ErrSendMessage returns when message to pageant cannt be sent + ErrSendMessage = errors.New("error sending message") + + // ErrMessageTooLong returns when message is too long (see MaxMessageLen) + ErrMessageTooLong = errors.New("message too long") + // ErrInvalidMessageFormat returns when message have invalid fomat + ErrInvalidMessageFormat = errors.New("invalid message format") + // ErrResponseTooLong returns when response from pageant is too long + ErrResponseTooLong = errors.New("response too long") +) + +///////////////////////// + +const ( + agentCopydataID = 0x804e50ba + wmCopydata = 74 +) + +type copyData struct { + dwData uintptr + cbData uint32 + lpData unsafe.Pointer +} + +var ( + lock sync.Mutex + + winFindWindow = winAPI("user32.dll", "FindWindowW") + winGetCurrentThreadID = winAPI("kernel32.dll", "GetCurrentThreadId") + winSendMessage = winAPI("user32.dll", "SendMessageW") +) + +func winAPI(dllName, funcName string) func(...uintptr) (uintptr, uintptr, error) { + proc := syscall.MustLoadDLL(dllName).MustFindProc(funcName) + return func(a ...uintptr) (uintptr, uintptr, error) { return proc.Call(a...) } +} + +// Available returns true if Pageant is started +func Available() bool { return pageantWindow() != 0 } + +// Query sends message msg to Pageant and returns response or error. +// 'msg' is raw agent request with length prefix +// Response is raw agent response with length prefix +func query(msg []byte) ([]byte, error) { + if len(msg) > MaxMessageLen { + return nil, ErrMessageTooLong + } + + msgLen := binary.BigEndian.Uint32(msg[:4]) + if len(msg) != int(msgLen)+4 { + return nil, ErrInvalidMessageFormat + } + + lock.Lock() + defer lock.Unlock() + + paWin := pageantWindow() + + if paWin == 0 { + return nil, ErrPageantNotFound + } + + thID, _, _ := winGetCurrentThreadID() + mapName := fmt.Sprintf("PageantRequest%08x", thID) + pMapName, _ := syscall.UTF16PtrFromString(mapName) + + mmap, err := syscall.CreateFileMapping(syscall.InvalidHandle, nil, syscall.PAGE_READWRITE, 0, MaxMessageLen+4, pMapName) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(mmap) + + ptr, err := syscall.MapViewOfFile(mmap, syscall.FILE_MAP_WRITE, 0, 0, 0) + if err != nil { + return nil, err + } + defer syscall.UnmapViewOfFile(ptr) + + mmSlice := (*(*[MaxMessageLen]byte)(unsafe.Pointer(ptr)))[:] + + copy(mmSlice, msg) + + mapNameBytesZ := append([]byte(mapName), 0) + + cds := copyData{ + dwData: agentCopydataID, + cbData: uint32(len(mapNameBytesZ)), + lpData: unsafe.Pointer(&(mapNameBytesZ[0])), + } + + resp, _, _ := winSendMessage(paWin, wmCopydata, 0, uintptr(unsafe.Pointer(&cds))) + + if resp == 0 { + return nil, ErrSendMessage + } + + respLen := binary.BigEndian.Uint32(mmSlice[:4]) + if respLen > MaxMessageLen-4 { + return nil, ErrResponseTooLong + } + + respData := make([]byte, respLen+4) + copy(respData, mmSlice) + + return respData, nil +} + +func pageantWindow() uintptr { + nameP, _ := syscall.UTF16PtrFromString("Pageant") + h, _, _ := winFindWindow(uintptr(unsafe.Pointer(nameP)), uintptr(unsafe.Pointer(nameP))) + return h +} diff --git a/vendor/github.com/go-fed/httpsig/LICENSE b/vendor/github.com/go-fed/httpsig/LICENSE new file mode 100644 index 00000000000..a9e8aefadb8 --- /dev/null +++ b/vendor/github.com/go-fed/httpsig/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, go-fed +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/go-fed/httpsig/README.md b/vendor/github.com/go-fed/httpsig/README.md new file mode 100644 index 00000000000..3b83854000b --- /dev/null +++ b/vendor/github.com/go-fed/httpsig/README.md @@ -0,0 +1,94 @@ +# httpsig + +`go get github.com/go-fed/httpsig` + +Implementation of [HTTP Signatures](https://tools.ietf.org/html/draft-cavage-http-signatures). + +Supports many different combinations of MAC, HMAC signing of hash, or RSA +signing of hash schemes. Its goals are: + +* Have a very simple interface for signing and validating +* Support a variety of signing algorithms and combinations +* Support setting either headers (`Authorization` or `Signature`) +* Remaining flexible with headers included in the signing string +* Support both HTTP requests and responses +* Explicitly not support known-cryptographically weak algorithms +* Support automatic signing and validating Digest headers + +## How to use + +`import "github.com/go-fed/httpsig"` + +### Signing + +Signing a request or response requires creating a new `Signer` and using it: + +``` +func sign(privateKey crypto.PrivateKey, pubKeyId string, r *http.Request) error { + prefs := []httpsig.Algorithm{httpsig.RSA_SHA512, httpsig.RSA_SHA256} + digestAlgorithm := DigestSha256 + // The "Date" and "Digest" headers must already be set on r, as well as r.URL. + headersToSign := []string{httpsig.RequestTarget, "date", "digest"} + signer, chosenAlgo, err := httpsig.NewSigner(prefs, digestAlgorithm, headersToSign, httpsig.Signature) + if err != nil { + return err + } + // To sign the digest, we need to give the signer a copy of the body... + // ...but it is optional, no digest will be signed if given "nil" + body := ... + // If r were a http.ResponseWriter, call SignResponse instead. + return signer.SignRequest(privateKey, pubKeyId, r, body) +} +``` + +`Signer`s are not safe for concurrent use by goroutines, so be sure to guard +access: + +``` +type server struct { + signer httpsig.Signer + mu *sync.Mutex +} + +func (s *server) handlerFunc(w http.ResponseWriter, r *http.Request) { + privateKey := ... + pubKeyId := ... + // Set headers and such on w + s.mu.Lock() + defer s.mu.Unlock() + // To sign the digest, we need to give the signer a copy of the response body... + // ...but it is optional, no digest will be signed if given "nil" + body := ... + err := s.signer.SignResponse(privateKey, pubKeyId, w, body) + if err != nil { + ... + } + ... +} +``` + +The `pubKeyId` will be used at verification time. + +### Verifying + +Verifying requires an application to use the `pubKeyId` to both retrieve the key +needed for verification as well as determine the algorithm to use. Use a +`Verifier`: + +``` +func verify(r *http.Request) error { + verifier, err := httpsig.NewVerifier(r) + if err != nil { + return err + } + pubKeyId := verifier.KeyId() + var algo httpsig.Algorithm = ... + var pubKey crypto.PublicKey = ... + // The verifier will verify the Digest in addition to the HTTP signature + return verifier.Verify(pubKey, algo) +} +``` + +`Verifier`s are not safe for concurrent use by goroutines, but since they are +constructed on a per-request or per-response basis it should not be a common +restriction. diff --git a/vendor/github.com/go-fed/httpsig/algorithms.go b/vendor/github.com/go-fed/httpsig/algorithms.go new file mode 100644 index 00000000000..9595941be8c --- /dev/null +++ b/vendor/github.com/go-fed/httpsig/algorithms.go @@ -0,0 +1,532 @@ +package httpsig + +import ( + "crypto" + "crypto/ecdsa" + "crypto/hmac" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "crypto/subtle" // Use should trigger great care + "encoding/asn1" + "errors" + "fmt" + "hash" + "io" + "math/big" + "strings" + + "golang.org/x/crypto/blake2b" + "golang.org/x/crypto/blake2s" + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/ripemd160" + "golang.org/x/crypto/sha3" + "golang.org/x/crypto/ssh" +) + +const ( + hmacPrefix = "hmac" + rsaPrefix = "rsa" + sshPrefix = "ssh" + ecdsaPrefix = "ecdsa" + ed25519Prefix = "ed25519" + md4String = "md4" + md5String = "md5" + sha1String = "sha1" + sha224String = "sha224" + sha256String = "sha256" + sha384String = "sha384" + sha512String = "sha512" + md5sha1String = "md5sha1" + ripemd160String = "ripemd160" + sha3_224String = "sha3-224" + sha3_256String = "sha3-256" + sha3_384String = "sha3-384" + sha3_512String = "sha3-512" + sha512_224String = "sha512-224" + sha512_256String = "sha512-256" + blake2s_256String = "blake2s-256" + blake2b_256String = "blake2b-256" + blake2b_384String = "blake2b-384" + blake2b_512String = "blake2b-512" +) + +var blake2Algorithms = map[crypto.Hash]bool{ + crypto.BLAKE2s_256: true, + crypto.BLAKE2b_256: true, + crypto.BLAKE2b_384: true, + crypto.BLAKE2b_512: true, +} + +var hashToDef = map[crypto.Hash]struct { + name string + new func(key []byte) (hash.Hash, error) // Only MACers will accept a key +}{ + // Which standard names these? + // The spec lists the following as a canonical reference, which is dead: + // http://www.iana.org/assignments/signature-algorithms + // + // Note that the forbidden hashes have an invalid 'new' function. + crypto.MD4: {md4String, func(key []byte) (hash.Hash, error) { return nil, nil }}, + crypto.MD5: {md5String, func(key []byte) (hash.Hash, error) { return nil, nil }}, + // Temporarily enable SHA1 because of issue https://github.com/golang/go/issues/37278 + crypto.SHA1: {sha1String, func(key []byte) (hash.Hash, error) { return sha1.New(), nil }}, + crypto.SHA224: {sha224String, func(key []byte) (hash.Hash, error) { return sha256.New224(), nil }}, + crypto.SHA256: {sha256String, func(key []byte) (hash.Hash, error) { return sha256.New(), nil }}, + crypto.SHA384: {sha384String, func(key []byte) (hash.Hash, error) { return sha512.New384(), nil }}, + crypto.SHA512: {sha512String, func(key []byte) (hash.Hash, error) { return sha512.New(), nil }}, + crypto.MD5SHA1: {md5sha1String, func(key []byte) (hash.Hash, error) { return nil, nil }}, + crypto.RIPEMD160: {ripemd160String, func(key []byte) (hash.Hash, error) { return ripemd160.New(), nil }}, + crypto.SHA3_224: {sha3_224String, func(key []byte) (hash.Hash, error) { return sha3.New224(), nil }}, + crypto.SHA3_256: {sha3_256String, func(key []byte) (hash.Hash, error) { return sha3.New256(), nil }}, + crypto.SHA3_384: {sha3_384String, func(key []byte) (hash.Hash, error) { return sha3.New384(), nil }}, + crypto.SHA3_512: {sha3_512String, func(key []byte) (hash.Hash, error) { return sha3.New512(), nil }}, + crypto.SHA512_224: {sha512_224String, func(key []byte) (hash.Hash, error) { return sha512.New512_224(), nil }}, + crypto.SHA512_256: {sha512_256String, func(key []byte) (hash.Hash, error) { return sha512.New512_256(), nil }}, + crypto.BLAKE2s_256: {blake2s_256String, func(key []byte) (hash.Hash, error) { return blake2s.New256(key) }}, + crypto.BLAKE2b_256: {blake2b_256String, func(key []byte) (hash.Hash, error) { return blake2b.New256(key) }}, + crypto.BLAKE2b_384: {blake2b_384String, func(key []byte) (hash.Hash, error) { return blake2b.New384(key) }}, + crypto.BLAKE2b_512: {blake2b_512String, func(key []byte) (hash.Hash, error) { return blake2b.New512(key) }}, +} + +var stringToHash map[string]crypto.Hash + +const ( + defaultAlgorithm = RSA_SHA256 + defaultAlgorithmHashing = sha256String +) + +func init() { + stringToHash = make(map[string]crypto.Hash, len(hashToDef)) + for k, v := range hashToDef { + stringToHash[v.name] = k + } + // This should guarantee that at runtime the defaultAlgorithm will not + // result in errors when fetching a macer or signer (see algorithms.go) + if ok, err := isAvailable(string(defaultAlgorithmHashing)); err != nil { + panic(err) + } else if !ok { + panic(fmt.Sprintf("the default httpsig algorithm is unavailable: %q", defaultAlgorithm)) + } +} + +func isForbiddenHash(h crypto.Hash) bool { + switch h { + // Not actually cryptographically secure + case crypto.MD4: + fallthrough + case crypto.MD5: + fallthrough + case crypto.MD5SHA1: // shorthand for crypto/tls, not actually implemented + return true + } + // Still cryptographically secure + return false +} + +// signer is an internally public type. +type signer interface { + Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) + Verify(pub crypto.PublicKey, toHash, signature []byte) error + String() string +} + +// macer is an internally public type. +type macer interface { + Sign(sig, key []byte) ([]byte, error) + Equal(sig, actualMAC, key []byte) (bool, error) + String() string +} + +var _ macer = &hmacAlgorithm{} + +type hmacAlgorithm struct { + fn func(key []byte) (hash.Hash, error) + kind crypto.Hash +} + +func (h *hmacAlgorithm) Sign(sig, key []byte) ([]byte, error) { + hs, err := h.fn(key) + if err = setSig(hs, sig); err != nil { + return nil, err + } + return hs.Sum(nil), nil +} + +func (h *hmacAlgorithm) Equal(sig, actualMAC, key []byte) (bool, error) { + hs, err := h.fn(key) + if err != nil { + return false, err + } + defer hs.Reset() + err = setSig(hs, sig) + if err != nil { + return false, err + } + expected := hs.Sum(nil) + return hmac.Equal(actualMAC, expected), nil +} + +func (h *hmacAlgorithm) String() string { + return fmt.Sprintf("%s-%s", hmacPrefix, hashToDef[h.kind].name) +} + +var _ signer = &rsaAlgorithm{} + +type rsaAlgorithm struct { + hash.Hash + kind crypto.Hash + sshSigner ssh.Signer +} + +func (r *rsaAlgorithm) setSig(b []byte) error { + n, err := r.Write(b) + if err != nil { + r.Reset() + return err + } else if n != len(b) { + r.Reset() + return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b)) + } + return nil +} + +func (r *rsaAlgorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) { + if r.sshSigner != nil { + sshsig, err := r.sshSigner.Sign(rand, sig) + if err != nil { + return nil, err + } + + return sshsig.Blob, nil + } + defer r.Reset() + + if err := r.setSig(sig); err != nil { + return nil, err + } + rsaK, ok := p.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("crypto.PrivateKey is not *rsa.PrivateKey") + } + return rsa.SignPKCS1v15(rand, rsaK, r.kind, r.Sum(nil)) +} + +func (r *rsaAlgorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error { + defer r.Reset() + rsaK, ok := pub.(*rsa.PublicKey) + if !ok { + return errors.New("crypto.PublicKey is not *rsa.PublicKey") + } + if err := r.setSig(toHash); err != nil { + return err + } + return rsa.VerifyPKCS1v15(rsaK, r.kind, r.Sum(nil), signature) +} + +func (r *rsaAlgorithm) String() string { + return fmt.Sprintf("%s-%s", rsaPrefix, hashToDef[r.kind].name) +} + +var _ signer = &ed25519Algorithm{} + +type ed25519Algorithm struct { + sshSigner ssh.Signer +} + +func (r *ed25519Algorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) { + if r.sshSigner != nil { + sshsig, err := r.sshSigner.Sign(rand, sig) + if err != nil { + return nil, err + } + + return sshsig.Blob, nil + } + ed25519K, ok := p.(ed25519.PrivateKey) + if !ok { + return nil, errors.New("crypto.PrivateKey is not ed25519.PrivateKey") + } + return ed25519.Sign(ed25519K, sig), nil +} + +func (r *ed25519Algorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error { + ed25519K, ok := pub.(ed25519.PublicKey) + if !ok { + return errors.New("crypto.PublicKey is not ed25519.PublicKey") + } + + if ed25519.Verify(ed25519K, toHash, signature) { + return nil + } + + return errors.New("ed25519 verify failed") +} + +func (r *ed25519Algorithm) String() string { + return fmt.Sprintf("%s", ed25519Prefix) +} + +var _ signer = &ecdsaAlgorithm{} + +type ecdsaAlgorithm struct { + hash.Hash + kind crypto.Hash +} + +func (r *ecdsaAlgorithm) setSig(b []byte) error { + n, err := r.Write(b) + if err != nil { + r.Reset() + return err + } else if n != len(b) { + r.Reset() + return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b)) + } + return nil +} + +type ECDSASignature struct { + R, S *big.Int +} + +func (r *ecdsaAlgorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) { + defer r.Reset() + if err := r.setSig(sig); err != nil { + return nil, err + } + ecdsaK, ok := p.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("crypto.PrivateKey is not *ecdsa.PrivateKey") + } + R, S, err := ecdsa.Sign(rand, ecdsaK, r.Sum(nil)) + if err != nil { + return nil, err + } + + signature := ECDSASignature{R: R, S: S} + bytes, err := asn1.Marshal(signature) + + return bytes, err +} + +func (r *ecdsaAlgorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error { + defer r.Reset() + ecdsaK, ok := pub.(*ecdsa.PublicKey) + if !ok { + return errors.New("crypto.PublicKey is not *ecdsa.PublicKey") + } + if err := r.setSig(toHash); err != nil { + return err + } + + sig := new(ECDSASignature) + _, err := asn1.Unmarshal(signature, sig) + if err != nil { + return err + } + + if ecdsa.Verify(ecdsaK, r.Sum(nil), sig.R, sig.S) { + return nil + } else { + return errors.New("Invalid signature") + } +} + +func (r *ecdsaAlgorithm) String() string { + return fmt.Sprintf("%s-%s", ecdsaPrefix, hashToDef[r.kind].name) +} + +var _ macer = &blakeMacAlgorithm{} + +type blakeMacAlgorithm struct { + fn func(key []byte) (hash.Hash, error) + kind crypto.Hash +} + +func (r *blakeMacAlgorithm) Sign(sig, key []byte) ([]byte, error) { + hs, err := r.fn(key) + if err != nil { + return nil, err + } + if err = setSig(hs, sig); err != nil { + return nil, err + } + return hs.Sum(nil), nil +} + +func (r *blakeMacAlgorithm) Equal(sig, actualMAC, key []byte) (bool, error) { + hs, err := r.fn(key) + if err != nil { + return false, err + } + defer hs.Reset() + err = setSig(hs, sig) + if err != nil { + return false, err + } + expected := hs.Sum(nil) + return subtle.ConstantTimeCompare(actualMAC, expected) == 1, nil +} + +func (r *blakeMacAlgorithm) String() string { + return fmt.Sprintf("%s", hashToDef[r.kind].name) +} + +func setSig(a hash.Hash, b []byte) error { + n, err := a.Write(b) + if err != nil { + a.Reset() + return err + } else if n != len(b) { + a.Reset() + return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b)) + } + return nil +} + +// IsSupportedHttpSigAlgorithm returns true if the string is supported by this +// library, is not a hash known to be weak, and is supported by the hardware. +func IsSupportedHttpSigAlgorithm(algo string) bool { + a, err := isAvailable(algo) + return a && err == nil +} + +// isAvailable is an internally public function +func isAvailable(algo string) (bool, error) { + c, ok := stringToHash[algo] + if !ok { + return false, fmt.Errorf("no match for %q", algo) + } + if isForbiddenHash(c) { + return false, fmt.Errorf("forbidden hash type in %q", algo) + } + return c.Available(), nil +} + +func newAlgorithmConstructor(algo string) (fn func(k []byte) (hash.Hash, error), c crypto.Hash, e error) { + ok := false + c, ok = stringToHash[algo] + if !ok { + e = fmt.Errorf("no match for %q", algo) + return + } + if isForbiddenHash(c) { + e = fmt.Errorf("forbidden hash type in %q", algo) + return + } + algoDef, ok := hashToDef[c] + if !ok { + e = fmt.Errorf("have crypto.Hash %v but no definition", c) + return + } + fn = func(key []byte) (hash.Hash, error) { + h, err := algoDef.new(key) + if err != nil { + return nil, err + } + return h, nil + } + return +} + +func newAlgorithm(algo string, key []byte) (hash.Hash, crypto.Hash, error) { + fn, c, err := newAlgorithmConstructor(algo) + if err != nil { + return nil, c, err + } + h, err := fn(key) + return h, c, err +} + +func signerFromSSHSigner(sshSigner ssh.Signer, s string) (signer, error) { + switch { + case strings.HasPrefix(s, rsaPrefix): + return &rsaAlgorithm{ + sshSigner: sshSigner, + }, nil + case strings.HasPrefix(s, ed25519Prefix): + return &ed25519Algorithm{ + sshSigner: sshSigner, + }, nil + default: + return nil, fmt.Errorf("no signer matching %q", s) + } +} + +// signerFromString is an internally public method constructor +func signerFromString(s string) (signer, error) { + s = strings.ToLower(s) + isEcdsa := false + isEd25519 := false + var algo string = "" + if strings.HasPrefix(s, ecdsaPrefix) { + algo = strings.TrimPrefix(s, ecdsaPrefix+"-") + isEcdsa = true + } else if strings.HasPrefix(s, rsaPrefix) { + algo = strings.TrimPrefix(s, rsaPrefix+"-") + } else if strings.HasPrefix(s, ed25519Prefix) { + isEd25519 = true + algo = "sha512" + } else { + return nil, fmt.Errorf("no signer matching %q", s) + } + hash, cHash, err := newAlgorithm(algo, nil) + if err != nil { + return nil, err + } + if isEd25519 { + return &ed25519Algorithm{}, nil + } + if isEcdsa { + return &ecdsaAlgorithm{ + Hash: hash, + kind: cHash, + }, nil + } + return &rsaAlgorithm{ + Hash: hash, + kind: cHash, + }, nil +} + +// macerFromString is an internally public method constructor +func macerFromString(s string) (macer, error) { + s = strings.ToLower(s) + if strings.HasPrefix(s, hmacPrefix) { + algo := strings.TrimPrefix(s, hmacPrefix+"-") + hashFn, cHash, err := newAlgorithmConstructor(algo) + if err != nil { + return nil, err + } + // Ensure below does not panic + _, err = hashFn(nil) + if err != nil { + return nil, err + } + return &hmacAlgorithm{ + fn: func(key []byte) (hash.Hash, error) { + return hmac.New(func() hash.Hash { + h, e := hashFn(nil) + if e != nil { + panic(e) + } + return h + }, key), nil + }, + kind: cHash, + }, nil + } else if bl, ok := stringToHash[s]; ok && blake2Algorithms[bl] { + hashFn, cHash, err := newAlgorithmConstructor(s) + if err != nil { + return nil, err + } + return &blakeMacAlgorithm{ + fn: hashFn, + kind: cHash, + }, nil + } else { + return nil, fmt.Errorf("no MACer matching %q", s) + } +} diff --git a/vendor/github.com/go-fed/httpsig/digest.go b/vendor/github.com/go-fed/httpsig/digest.go new file mode 100644 index 00000000000..bf9e3a914cc --- /dev/null +++ b/vendor/github.com/go-fed/httpsig/digest.go @@ -0,0 +1,120 @@ +package httpsig + +import ( + "bytes" + "crypto" + "encoding/base64" + "fmt" + "hash" + "net/http" + "strings" +) + +type DigestAlgorithm string + +const ( + DigestSha256 DigestAlgorithm = "SHA-256" + DigestSha512 = "SHA-512" +) + +var digestToDef = map[DigestAlgorithm]crypto.Hash{ + DigestSha256: crypto.SHA256, + DigestSha512: crypto.SHA512, +} + +// IsSupportedDigestAlgorithm returns true if hte string is supported by this +// library, is not a hash known to be weak, and is supported by the hardware. +func IsSupportedDigestAlgorithm(algo string) bool { + uc := DigestAlgorithm(strings.ToUpper(algo)) + c, ok := digestToDef[uc] + return ok && c.Available() +} + +func getHash(alg DigestAlgorithm) (h hash.Hash, toUse DigestAlgorithm, err error) { + upper := DigestAlgorithm(strings.ToUpper(string(alg))) + c, ok := digestToDef[upper] + if !ok { + err = fmt.Errorf("unknown or unsupported Digest algorithm: %s", alg) + } else if !c.Available() { + err = fmt.Errorf("unavailable Digest algorithm: %s", alg) + } else { + h = c.New() + toUse = upper + } + return +} + +const ( + digestHeader = "Digest" + digestDelim = "=" +) + +func addDigest(r *http.Request, algo DigestAlgorithm, b []byte) (err error) { + _, ok := r.Header[digestHeader] + if ok { + err = fmt.Errorf("cannot add Digest: Digest is already set") + return + } + var h hash.Hash + var a DigestAlgorithm + h, a, err = getHash(algo) + if err != nil { + return + } + h.Write(b) + sum := h.Sum(nil) + r.Header.Add(digestHeader, + fmt.Sprintf("%s%s%s", + a, + digestDelim, + base64.StdEncoding.EncodeToString(sum[:]))) + return +} + +func addDigestResponse(r http.ResponseWriter, algo DigestAlgorithm, b []byte) (err error) { + _, ok := r.Header()[digestHeader] + if ok { + err = fmt.Errorf("cannot add Digest: Digest is already set") + return + } + var h hash.Hash + var a DigestAlgorithm + h, a, err = getHash(algo) + if err != nil { + return + } + h.Write(b) + sum := h.Sum(nil) + r.Header().Add(digestHeader, + fmt.Sprintf("%s%s%s", + a, + digestDelim, + base64.StdEncoding.EncodeToString(sum[:]))) + return +} + +func verifyDigest(r *http.Request, body *bytes.Buffer) (err error) { + d := r.Header.Get(digestHeader) + if len(d) == 0 { + err = fmt.Errorf("cannot verify Digest: request has no Digest header") + return + } + elem := strings.SplitN(d, digestDelim, 2) + if len(elem) != 2 { + err = fmt.Errorf("cannot verify Digest: malformed Digest: %s", d) + return + } + var h hash.Hash + h, _, err = getHash(DigestAlgorithm(elem[0])) + if err != nil { + return + } + h.Write(body.Bytes()) + sum := h.Sum(nil) + encSum := base64.StdEncoding.EncodeToString(sum[:]) + if encSum != elem[1] { + err = fmt.Errorf("cannot verify Digest: header Digest does not match the digest of the request body") + return + } + return +} diff --git a/vendor/github.com/go-fed/httpsig/httpsig.go b/vendor/github.com/go-fed/httpsig/httpsig.go new file mode 100644 index 00000000000..1a6b95463ad --- /dev/null +++ b/vendor/github.com/go-fed/httpsig/httpsig.go @@ -0,0 +1,361 @@ +// Implements HTTP request and response signing and verification. Supports the +// major MAC and asymmetric key signature algorithms. It has several safety +// restrictions: One, none of the widely known non-cryptographically safe +// algorithms are permitted; Two, the RSA SHA256 algorithms must be available in +// the binary (and it should, barring export restrictions); Finally, the library +// assumes either the 'Authorizationn' or 'Signature' headers are to be set (but +// not both). +package httpsig + +import ( + "crypto" + "fmt" + "net/http" + "strings" + "time" + + "golang.org/x/crypto/ssh" +) + +// Algorithm specifies a cryptography secure algorithm for signing HTTP requests +// and responses. +type Algorithm string + +const ( + // MAC-based algoirthms. + HMAC_SHA224 Algorithm = hmacPrefix + "-" + sha224String + HMAC_SHA256 Algorithm = hmacPrefix + "-" + sha256String + HMAC_SHA384 Algorithm = hmacPrefix + "-" + sha384String + HMAC_SHA512 Algorithm = hmacPrefix + "-" + sha512String + HMAC_RIPEMD160 Algorithm = hmacPrefix + "-" + ripemd160String + HMAC_SHA3_224 Algorithm = hmacPrefix + "-" + sha3_224String + HMAC_SHA3_256 Algorithm = hmacPrefix + "-" + sha3_256String + HMAC_SHA3_384 Algorithm = hmacPrefix + "-" + sha3_384String + HMAC_SHA3_512 Algorithm = hmacPrefix + "-" + sha3_512String + HMAC_SHA512_224 Algorithm = hmacPrefix + "-" + sha512_224String + HMAC_SHA512_256 Algorithm = hmacPrefix + "-" + sha512_256String + HMAC_BLAKE2S_256 Algorithm = hmacPrefix + "-" + blake2s_256String + HMAC_BLAKE2B_256 Algorithm = hmacPrefix + "-" + blake2b_256String + HMAC_BLAKE2B_384 Algorithm = hmacPrefix + "-" + blake2b_384String + HMAC_BLAKE2B_512 Algorithm = hmacPrefix + "-" + blake2b_512String + BLAKE2S_256 Algorithm = blake2s_256String + BLAKE2B_256 Algorithm = blake2b_256String + BLAKE2B_384 Algorithm = blake2b_384String + BLAKE2B_512 Algorithm = blake2b_512String + // RSA-based algorithms. + RSA_SHA1 Algorithm = rsaPrefix + "-" + sha1String + RSA_SHA224 Algorithm = rsaPrefix + "-" + sha224String + // RSA_SHA256 is the default algorithm. + RSA_SHA256 Algorithm = rsaPrefix + "-" + sha256String + RSA_SHA384 Algorithm = rsaPrefix + "-" + sha384String + RSA_SHA512 Algorithm = rsaPrefix + "-" + sha512String + RSA_RIPEMD160 Algorithm = rsaPrefix + "-" + ripemd160String + // ECDSA algorithms + ECDSA_SHA224 Algorithm = ecdsaPrefix + "-" + sha224String + ECDSA_SHA256 Algorithm = ecdsaPrefix + "-" + sha256String + ECDSA_SHA384 Algorithm = ecdsaPrefix + "-" + sha384String + ECDSA_SHA512 Algorithm = ecdsaPrefix + "-" + sha512String + ECDSA_RIPEMD160 Algorithm = ecdsaPrefix + "-" + ripemd160String + // ED25519 algorithms + // can only be SHA512 + ED25519 Algorithm = ed25519Prefix + + // Just because you can glue things together, doesn't mean they will + // work. The following options are not supported. + rsa_SHA3_224 Algorithm = rsaPrefix + "-" + sha3_224String + rsa_SHA3_256 Algorithm = rsaPrefix + "-" + sha3_256String + rsa_SHA3_384 Algorithm = rsaPrefix + "-" + sha3_384String + rsa_SHA3_512 Algorithm = rsaPrefix + "-" + sha3_512String + rsa_SHA512_224 Algorithm = rsaPrefix + "-" + sha512_224String + rsa_SHA512_256 Algorithm = rsaPrefix + "-" + sha512_256String + rsa_BLAKE2S_256 Algorithm = rsaPrefix + "-" + blake2s_256String + rsa_BLAKE2B_256 Algorithm = rsaPrefix + "-" + blake2b_256String + rsa_BLAKE2B_384 Algorithm = rsaPrefix + "-" + blake2b_384String + rsa_BLAKE2B_512 Algorithm = rsaPrefix + "-" + blake2b_512String +) + +// HTTP Signatures can be applied to different HTTP headers, depending on the +// expected application behavior. +type SignatureScheme string + +const ( + // Signature will place the HTTP Signature into the 'Signature' HTTP + // header. + Signature SignatureScheme = "Signature" + // Authorization will place the HTTP Signature into the 'Authorization' + // HTTP header. + Authorization SignatureScheme = "Authorization" +) + +const ( + // The HTTP Signatures specification uses the "Signature" auth-scheme + // for the Authorization header. This is coincidentally named, but not + // semantically the same, as the "Signature" HTTP header value. + signatureAuthScheme = "Signature" +) + +// There are subtle differences to the values in the header. The Authorization +// header has an 'auth-scheme' value that must be prefixed to the rest of the +// key and values. +func (s SignatureScheme) authScheme() string { + switch s { + case Authorization: + return signatureAuthScheme + default: + return "" + } +} + +// Signers will sign HTTP requests or responses based on the algorithms and +// headers selected at creation time. +// +// Signers are not safe to use between multiple goroutines. +// +// Note that signatures do set the deprecated 'algorithm' parameter for +// backwards compatibility. +type Signer interface { + // SignRequest signs the request using a private key. The public key id + // is used by the HTTP server to identify which key to use to verify the + // signature. + // + // If the Signer was created using a MAC based algorithm, then the key + // is expected to be of type []byte. If the Signer was created using an + // RSA based algorithm, then the private key is expected to be of type + // *rsa.PrivateKey. + // + // A Digest (RFC 3230) will be added to the request. The body provided + // must match the body used in the request, and is allowed to be nil. + // The Digest ensures the request body is not tampered with in flight, + // and if the signer is created to also sign the "Digest" header, the + // HTTP Signature will then ensure both the Digest and body are not both + // modified to maliciously represent different content. + SignRequest(pKey crypto.PrivateKey, pubKeyId string, r *http.Request, body []byte) error + // SignResponse signs the response using a private key. The public key + // id is used by the HTTP client to identify which key to use to verify + // the signature. + // + // If the Signer was created using a MAC based algorithm, then the key + // is expected to be of type []byte. If the Signer was created using an + // RSA based algorithm, then the private key is expected to be of type + // *rsa.PrivateKey. + // + // A Digest (RFC 3230) will be added to the response. The body provided + // must match the body written in the response, and is allowed to be + // nil. The Digest ensures the response body is not tampered with in + // flight, and if the signer is created to also sign the "Digest" + // header, the HTTP Signature will then ensure both the Digest and body + // are not both modified to maliciously represent different content. + SignResponse(pKey crypto.PrivateKey, pubKeyId string, r http.ResponseWriter, body []byte) error +} + +// NewSigner creates a new Signer with the provided algorithm preferences to +// make HTTP signatures. Only the first available algorithm will be used, which +// is returned by this function along with the Signer. If none of the preferred +// algorithms were available, then the default algorithm is used. The headers +// specified will be included into the HTTP signatures. +// +// The Digest will also be calculated on a request's body using the provided +// digest algorithm, if "Digest" is one of the headers listed. +// +// The provided scheme determines which header is populated with the HTTP +// Signature. +// +// An error is returned if an unknown or a known cryptographically insecure +// Algorithm is provided. +func NewSigner(prefs []Algorithm, dAlgo DigestAlgorithm, headers []string, scheme SignatureScheme, expiresIn int64) (Signer, Algorithm, error) { + for _, pref := range prefs { + s, err := newSigner(pref, dAlgo, headers, scheme, expiresIn) + if err != nil { + continue + } + return s, pref, err + } + s, err := newSigner(defaultAlgorithm, dAlgo, headers, scheme, expiresIn) + return s, defaultAlgorithm, err +} + +// Signers will sign HTTP requests or responses based on the algorithms and +// headers selected at creation time. +// +// Signers are not safe to use between multiple goroutines. +// +// Note that signatures do set the deprecated 'algorithm' parameter for +// backwards compatibility. +type SSHSigner interface { + // SignRequest signs the request using ssh.Signer. + // The public key id is used by the HTTP server to identify which key to use + // to verify the signature. + // + // A Digest (RFC 3230) will be added to the request. The body provided + // must match the body used in the request, and is allowed to be nil. + // The Digest ensures the request body is not tampered with in flight, + // and if the signer is created to also sign the "Digest" header, the + // HTTP Signature will then ensure both the Digest and body are not both + // modified to maliciously represent different content. + SignRequest(pubKeyId string, r *http.Request, body []byte) error + // SignResponse signs the response using ssh.Signer. The public key + // id is used by the HTTP client to identify which key to use to verify + // the signature. + // + // A Digest (RFC 3230) will be added to the response. The body provided + // must match the body written in the response, and is allowed to be + // nil. The Digest ensures the response body is not tampered with in + // flight, and if the signer is created to also sign the "Digest" + // header, the HTTP Signature will then ensure both the Digest and body + // are not both modified to maliciously represent different content. + SignResponse(pubKeyId string, r http.ResponseWriter, body []byte) error +} + +// NewwSSHSigner creates a new Signer using the specified ssh.Signer +// At the moment only ed25519 ssh keys are supported. +// The headers specified will be included into the HTTP signatures. +// +// The Digest will also be calculated on a request's body using the provided +// digest algorithm, if "Digest" is one of the headers listed. +// +// The provided scheme determines which header is populated with the HTTP +// Signature. +func NewSSHSigner(s ssh.Signer, dAlgo DigestAlgorithm, headers []string, scheme SignatureScheme, expiresIn int64) (SSHSigner, Algorithm, error) { + sshAlgo := getSSHAlgorithm(s.PublicKey().Type()) + if sshAlgo == "" { + return nil, "", fmt.Errorf("key type: %s not supported yet.", s.PublicKey().Type()) + } + + signer, err := newSSHSigner(s, sshAlgo, dAlgo, headers, scheme, expiresIn) + if err != nil { + return nil, "", err + } + + return signer, sshAlgo, nil +} + +func getSSHAlgorithm(pkType string) Algorithm { + switch { + case strings.HasPrefix(pkType, sshPrefix+"-"+ed25519Prefix): + return ED25519 + case strings.HasPrefix(pkType, sshPrefix+"-"+rsaPrefix): + return RSA_SHA1 + } + + return "" +} + +// Verifier verifies HTTP Signatures. +// +// It will determine which of the supported headers has the parameters +// that define the signature. +// +// Verifiers are not safe to use between multiple goroutines. +// +// Note that verification ignores the deprecated 'algorithm' parameter. +type Verifier interface { + // KeyId gets the public key id that the signature is signed with. + // + // Note that the application is expected to determine the algorithm + // used based on metadata or out-of-band information for this key id. + KeyId() string + // Verify accepts the public key specified by KeyId and returns an + // error if verification fails or if the signature is malformed. The + // algorithm must be the one used to create the signature in order to + // pass verification. The algorithm is determined based on metadata or + // out-of-band information for the key id. + // + // If the signature was created using a MAC based algorithm, then the + // key is expected to be of type []byte. If the signature was created + // using an RSA based algorithm, then the public key is expected to be + // of type *rsa.PublicKey. + Verify(pKey crypto.PublicKey, algo Algorithm) error +} + +const ( + // host is treated specially because golang may not include it in the + // request header map on the server side of a request. + hostHeader = "Host" +) + +// NewVerifier verifies the given request. It returns an error if the HTTP +// Signature parameters are not present in any headers, are present in more than +// one header, are malformed, or are missing required parameters. It ignores +// unknown HTTP Signature parameters. +func NewVerifier(r *http.Request) (Verifier, error) { + h := r.Header + if _, hasHostHeader := h[hostHeader]; len(r.Host) > 0 && !hasHostHeader { + h[hostHeader] = []string{r.Host} + } + return newVerifier(h, func(h http.Header, toInclude []string, created int64, expires int64) (string, error) { + return signatureString(h, toInclude, addRequestTarget(r), created, expires) + }) +} + +// NewResponseVerifier verifies the given response. It returns errors under the +// same conditions as NewVerifier. +func NewResponseVerifier(r *http.Response) (Verifier, error) { + return newVerifier(r.Header, func(h http.Header, toInclude []string, created int64, expires int64) (string, error) { + return signatureString(h, toInclude, requestTargetNotPermitted, created, expires) + }) +} + +func newSSHSigner(sshSigner ssh.Signer, algo Algorithm, dAlgo DigestAlgorithm, headers []string, scheme SignatureScheme, expiresIn int64) (SSHSigner, error) { + var expires, created int64 = 0, 0 + + if expiresIn != 0 { + created = time.Now().Unix() + expires = created + expiresIn + } + + s, err := signerFromSSHSigner(sshSigner, string(algo)) + if err != nil { + return nil, fmt.Errorf("no crypto implementation available for ssh algo %q", algo) + } + + a := &asymmSSHSigner{ + asymmSigner: &asymmSigner{ + s: s, + dAlgo: dAlgo, + headers: headers, + targetHeader: scheme, + prefix: scheme.authScheme(), + created: created, + expires: expires, + }, + } + + return a, nil +} + +func newSigner(algo Algorithm, dAlgo DigestAlgorithm, headers []string, scheme SignatureScheme, expiresIn int64) (Signer, error) { + + var expires, created int64 = 0, 0 + if expiresIn != 0 { + created = time.Now().Unix() + expires = created + expiresIn + } + + s, err := signerFromString(string(algo)) + if err == nil { + a := &asymmSigner{ + s: s, + dAlgo: dAlgo, + headers: headers, + targetHeader: scheme, + prefix: scheme.authScheme(), + created: created, + expires: expires, + } + return a, nil + } + m, err := macerFromString(string(algo)) + if err != nil { + return nil, fmt.Errorf("no crypto implementation available for %q", algo) + } + c := &macSigner{ + m: m, + dAlgo: dAlgo, + headers: headers, + targetHeader: scheme, + prefix: scheme.authScheme(), + created: created, + expires: expires, + } + return c, nil +} diff --git a/vendor/github.com/go-fed/httpsig/signing.go b/vendor/github.com/go-fed/httpsig/signing.go new file mode 100644 index 00000000000..e18db41cb22 --- /dev/null +++ b/vendor/github.com/go-fed/httpsig/signing.go @@ -0,0 +1,334 @@ +package httpsig + +import ( + "bytes" + "crypto" + "crypto/rand" + "encoding/base64" + "fmt" + "net/http" + "net/textproto" + "strconv" + "strings" +) + +const ( + // Signature Parameters + keyIdParameter = "keyId" + algorithmParameter = "algorithm" + headersParameter = "headers" + signatureParameter = "signature" + prefixSeparater = " " + parameterKVSeparater = "=" + parameterValueDelimiter = "\"" + parameterSeparater = "," + headerParameterValueDelim = " " + // RequestTarget specifies to include the http request method and + // entire URI in the signature. Pass it as a header to NewSigner. + RequestTarget = "(request-target)" + createdKey = "created" + expiresKey = "expires" + dateHeader = "date" + + // Signature String Construction + headerFieldDelimiter = ": " + headersDelimiter = "\n" + headerValueDelimiter = ", " + requestTargetSeparator = " " +) + +var defaultHeaders = []string{dateHeader} + +var _ Signer = &macSigner{} + +type macSigner struct { + m macer + makeDigest bool + dAlgo DigestAlgorithm + headers []string + targetHeader SignatureScheme + prefix string + created int64 + expires int64 +} + +func (m *macSigner) SignRequest(pKey crypto.PrivateKey, pubKeyId string, r *http.Request, body []byte) error { + if body != nil { + err := addDigest(r, m.dAlgo, body) + if err != nil { + return err + } + } + s, err := m.signatureString(r) + if err != nil { + return err + } + enc, err := m.signSignature(pKey, s) + if err != nil { + return err + } + setSignatureHeader(r.Header, string(m.targetHeader), m.prefix, pubKeyId, m.m.String(), enc, m.headers, m.created, m.expires) + return nil +} + +func (m *macSigner) SignResponse(pKey crypto.PrivateKey, pubKeyId string, r http.ResponseWriter, body []byte) error { + if body != nil { + err := addDigestResponse(r, m.dAlgo, body) + if err != nil { + return err + } + } + s, err := m.signatureStringResponse(r) + if err != nil { + return err + } + enc, err := m.signSignature(pKey, s) + if err != nil { + return err + } + setSignatureHeader(r.Header(), string(m.targetHeader), m.prefix, pubKeyId, m.m.String(), enc, m.headers, m.created, m.expires) + return nil +} + +func (m *macSigner) signSignature(pKey crypto.PrivateKey, s string) (string, error) { + pKeyBytes, ok := pKey.([]byte) + if !ok { + return "", fmt.Errorf("private key for MAC signing must be of type []byte") + } + sig, err := m.m.Sign([]byte(s), pKeyBytes) + if err != nil { + return "", err + } + enc := base64.StdEncoding.EncodeToString(sig) + return enc, nil +} + +func (m *macSigner) signatureString(r *http.Request) (string, error) { + return signatureString(r.Header, m.headers, addRequestTarget(r), m.created, m.expires) +} + +func (m *macSigner) signatureStringResponse(r http.ResponseWriter) (string, error) { + return signatureString(r.Header(), m.headers, requestTargetNotPermitted, m.created, m.expires) +} + +var _ Signer = &asymmSigner{} + +type asymmSigner struct { + s signer + makeDigest bool + dAlgo DigestAlgorithm + headers []string + targetHeader SignatureScheme + prefix string + created int64 + expires int64 +} + +func (a *asymmSigner) SignRequest(pKey crypto.PrivateKey, pubKeyId string, r *http.Request, body []byte) error { + if body != nil { + err := addDigest(r, a.dAlgo, body) + if err != nil { + return err + } + } + s, err := a.signatureString(r) + if err != nil { + return err + } + enc, err := a.signSignature(pKey, s) + if err != nil { + return err + } + setSignatureHeader(r.Header, string(a.targetHeader), a.prefix, pubKeyId, a.s.String(), enc, a.headers, a.created, a.expires) + return nil +} + +func (a *asymmSigner) SignResponse(pKey crypto.PrivateKey, pubKeyId string, r http.ResponseWriter, body []byte) error { + if body != nil { + err := addDigestResponse(r, a.dAlgo, body) + if err != nil { + return err + } + } + s, err := a.signatureStringResponse(r) + if err != nil { + return err + } + enc, err := a.signSignature(pKey, s) + if err != nil { + return err + } + setSignatureHeader(r.Header(), string(a.targetHeader), a.prefix, pubKeyId, a.s.String(), enc, a.headers, a.created, a.expires) + return nil +} + +func (a *asymmSigner) signSignature(pKey crypto.PrivateKey, s string) (string, error) { + sig, err := a.s.Sign(rand.Reader, pKey, []byte(s)) + if err != nil { + return "", err + } + enc := base64.StdEncoding.EncodeToString(sig) + return enc, nil +} + +func (a *asymmSigner) signatureString(r *http.Request) (string, error) { + return signatureString(r.Header, a.headers, addRequestTarget(r), a.created, a.expires) +} + +func (a *asymmSigner) signatureStringResponse(r http.ResponseWriter) (string, error) { + return signatureString(r.Header(), a.headers, requestTargetNotPermitted, a.created, a.expires) +} + +var _ SSHSigner = &asymmSSHSigner{} + +type asymmSSHSigner struct { + *asymmSigner +} + +func (a *asymmSSHSigner) SignRequest(pubKeyId string, r *http.Request, body []byte) error { + return a.asymmSigner.SignRequest(nil, pubKeyId, r, body) +} + +func (a *asymmSSHSigner) SignResponse(pubKeyId string, r http.ResponseWriter, body []byte) error { + return a.asymmSigner.SignResponse(nil, pubKeyId, r, body) +} + +func setSignatureHeader(h http.Header, targetHeader, prefix, pubKeyId, algo, enc string, headers []string, created int64, expires int64) { + if len(headers) == 0 { + headers = defaultHeaders + } + var b bytes.Buffer + // KeyId + b.WriteString(prefix) + if len(prefix) > 0 { + b.WriteString(prefixSeparater) + } + b.WriteString(keyIdParameter) + b.WriteString(parameterKVSeparater) + b.WriteString(parameterValueDelimiter) + b.WriteString(pubKeyId) + b.WriteString(parameterValueDelimiter) + b.WriteString(parameterSeparater) + // Algorithm + b.WriteString(algorithmParameter) + b.WriteString(parameterKVSeparater) + b.WriteString(parameterValueDelimiter) + b.WriteString("hs2019") //real algorithm is hidden, see newest version of spec draft + b.WriteString(parameterValueDelimiter) + b.WriteString(parameterSeparater) + + hasCreated := false + hasExpires := false + for _, h := range headers { + val := strings.ToLower(h) + if val == "("+createdKey+")" { + hasCreated = true + } else if val == "("+expiresKey+")" { + hasExpires = true + } + } + + // Created + if hasCreated == true { + b.WriteString(createdKey) + b.WriteString(parameterKVSeparater) + b.WriteString(strconv.FormatInt(created, 10)) + b.WriteString(parameterSeparater) + } + + // Expires + if hasExpires == true { + b.WriteString(expiresKey) + b.WriteString(parameterKVSeparater) + b.WriteString(strconv.FormatInt(expires, 10)) + b.WriteString(parameterSeparater) + } + + // Headers + b.WriteString(headersParameter) + b.WriteString(parameterKVSeparater) + b.WriteString(parameterValueDelimiter) + for i, h := range headers { + b.WriteString(strings.ToLower(h)) + if i != len(headers)-1 { + b.WriteString(headerParameterValueDelim) + } + } + b.WriteString(parameterValueDelimiter) + b.WriteString(parameterSeparater) + // Signature + b.WriteString(signatureParameter) + b.WriteString(parameterKVSeparater) + b.WriteString(parameterValueDelimiter) + b.WriteString(enc) + b.WriteString(parameterValueDelimiter) + h.Add(targetHeader, b.String()) +} + +func requestTargetNotPermitted(b *bytes.Buffer) error { + return fmt.Errorf("cannot sign with %q on anything other than an http request", RequestTarget) +} + +func addRequestTarget(r *http.Request) func(b *bytes.Buffer) error { + return func(b *bytes.Buffer) error { + b.WriteString(RequestTarget) + b.WriteString(headerFieldDelimiter) + b.WriteString(strings.ToLower(r.Method)) + b.WriteString(requestTargetSeparator) + b.WriteString(r.URL.Path) + + if r.URL.RawQuery != "" { + b.WriteString("?") + b.WriteString(r.URL.RawQuery) + } + + return nil + } +} + +func signatureString(values http.Header, include []string, requestTargetFn func(b *bytes.Buffer) error, created int64, expires int64) (string, error) { + if len(include) == 0 { + include = defaultHeaders + } + var b bytes.Buffer + for n, i := range include { + i := strings.ToLower(i) + if i == RequestTarget { + err := requestTargetFn(&b) + if err != nil { + return "", err + } + } else if i == "("+expiresKey+")" { + if expires == 0 { + return "", fmt.Errorf("missing expires value") + } + b.WriteString(i) + b.WriteString(headerFieldDelimiter) + b.WriteString(strconv.FormatInt(expires, 10)) + } else if i == "("+createdKey+")" { + if created == 0 { + return "", fmt.Errorf("missing created value") + } + b.WriteString(i) + b.WriteString(headerFieldDelimiter) + b.WriteString(strconv.FormatInt(created, 10)) + } else { + hv, ok := values[textproto.CanonicalMIMEHeaderKey(i)] + if !ok { + return "", fmt.Errorf("missing header %q", i) + } + b.WriteString(i) + b.WriteString(headerFieldDelimiter) + for i, v := range hv { + b.WriteString(strings.TrimSpace(v)) + if i < len(hv)-1 { + b.WriteString(headerValueDelimiter) + } + } + } + if n < len(include)-1 { + b.WriteString(headersDelimiter) + } + } + return b.String(), nil +} diff --git a/vendor/github.com/go-fed/httpsig/verifying.go b/vendor/github.com/go-fed/httpsig/verifying.go new file mode 100644 index 00000000000..6d8df02cefa --- /dev/null +++ b/vendor/github.com/go-fed/httpsig/verifying.go @@ -0,0 +1,184 @@ +package httpsig + +import ( + "crypto" + "encoding/base64" + "errors" + "fmt" + "net/http" + "strconv" + "strings" + "time" +) + +var _ Verifier = &verifier{} + +type verifier struct { + header http.Header + kId string + signature string + created int64 + expires int64 + headers []string + sigStringFn func(http.Header, []string, int64, int64) (string, error) +} + +func newVerifier(h http.Header, sigStringFn func(http.Header, []string, int64, int64) (string, error)) (*verifier, error) { + scheme, s, err := getSignatureScheme(h) + if err != nil { + return nil, err + } + kId, sig, headers, created, expires, err := getSignatureComponents(scheme, s) + if created != 0 { + //check if created is not in the future, we assume a maximum clock offset of 10 seconds + now := time.Now().Unix() + if created-now > 10 { + return nil, errors.New("created is in the future") + } + } + if expires != 0 { + //check if expires is in the past, we assume a maximum clock offset of 10 seconds + now := time.Now().Unix() + if now-expires > 10 { + return nil, errors.New("signature expired") + } + } + if err != nil { + return nil, err + } + return &verifier{ + header: h, + kId: kId, + signature: sig, + created: created, + expires: expires, + headers: headers, + sigStringFn: sigStringFn, + }, nil +} + +func (v *verifier) KeyId() string { + return v.kId +} + +func (v *verifier) Verify(pKey crypto.PublicKey, algo Algorithm) error { + s, err := signerFromString(string(algo)) + if err == nil { + return v.asymmVerify(s, pKey) + } + m, err := macerFromString(string(algo)) + if err == nil { + return v.macVerify(m, pKey) + } + return fmt.Errorf("no crypto implementation available for %q", algo) +} + +func (v *verifier) macVerify(m macer, pKey crypto.PublicKey) error { + key, ok := pKey.([]byte) + if !ok { + return fmt.Errorf("public key for MAC verifying must be of type []byte") + } + signature, err := v.sigStringFn(v.header, v.headers, v.created, v.expires) + if err != nil { + return err + } + actualMAC, err := base64.StdEncoding.DecodeString(v.signature) + if err != nil { + return err + } + ok, err = m.Equal([]byte(signature), actualMAC, key) + if err != nil { + return err + } else if !ok { + return fmt.Errorf("invalid http signature") + } + return nil +} + +func (v *verifier) asymmVerify(s signer, pKey crypto.PublicKey) error { + toHash, err := v.sigStringFn(v.header, v.headers, v.created, v.expires) + if err != nil { + return err + } + signature, err := base64.StdEncoding.DecodeString(v.signature) + if err != nil { + return err + } + err = s.Verify(pKey, []byte(toHash), signature) + if err != nil { + return err + } + return nil +} + +func getSignatureScheme(h http.Header) (scheme SignatureScheme, val string, err error) { + s := h.Get(string(Signature)) + sigHasAll := strings.Contains(s, keyIdParameter) || + strings.Contains(s, headersParameter) || + strings.Contains(s, signatureParameter) + a := h.Get(string(Authorization)) + authHasAll := strings.Contains(a, keyIdParameter) || + strings.Contains(a, headersParameter) || + strings.Contains(a, signatureParameter) + if sigHasAll && authHasAll { + err = fmt.Errorf("both %q and %q have signature parameters", Signature, Authorization) + return + } else if !sigHasAll && !authHasAll { + err = fmt.Errorf("neither %q nor %q have signature parameters", Signature, Authorization) + return + } else if sigHasAll { + val = s + scheme = Signature + return + } else { // authHasAll + val = a + scheme = Authorization + return + } +} + +func getSignatureComponents(scheme SignatureScheme, s string) (kId, sig string, headers []string, created int64, expires int64, err error) { + if as := scheme.authScheme(); len(as) > 0 { + s = strings.TrimPrefix(s, as+prefixSeparater) + } + params := strings.Split(s, parameterSeparater) + for _, p := range params { + kv := strings.SplitN(p, parameterKVSeparater, 2) + if len(kv) != 2 { + err = fmt.Errorf("malformed http signature parameter: %v", kv) + return + } + k := kv[0] + v := strings.Trim(kv[1], parameterValueDelimiter) + switch k { + case keyIdParameter: + kId = v + case createdKey: + created, err = strconv.ParseInt(v, 10, 64) + if err != nil { + return + } + case expiresKey: + expires, err = strconv.ParseInt(v, 10, 64) + if err != nil { + return + } + case algorithmParameter: + // Deprecated, ignore + case headersParameter: + headers = strings.Split(v, headerParameterValueDelim) + case signatureParameter: + sig = v + default: + // Ignore unrecognized parameters + } + } + if len(kId) == 0 { + err = fmt.Errorf("missing %q parameter in http signature", keyIdParameter) + } else if len(sig) == 0 { + err = fmt.Errorf("missing %q parameter in http signature", signatureParameter) + } else if len(headers) == 0 { // Optional + headers = defaultHeaders + } + return +} diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s.go b/vendor/golang.org/x/crypto/blake2s/blake2s.go new file mode 100644 index 00000000000..e3f46aab3a1 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2s.go @@ -0,0 +1,246 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package blake2s implements the BLAKE2s hash algorithm defined by RFC 7693 +// and the extendable output function (XOF) BLAKE2Xs. +// +// BLAKE2s is optimized for 8- to 32-bit platforms and produces digests of any +// size between 1 and 32 bytes. +// For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf +// and for BLAKE2Xs see https://blake2.net/blake2x.pdf +// +// If you aren't sure which function you need, use BLAKE2s (Sum256 or New256). +// If you need a secret-key MAC (message authentication code), use the New256 +// function with a non-nil key. +// +// BLAKE2X is a construction to compute hash values larger than 32 bytes. It +// can produce hash values between 0 and 65535 bytes. +package blake2s // import "golang.org/x/crypto/blake2s" + +import ( + "encoding/binary" + "errors" + "hash" +) + +const ( + // The blocksize of BLAKE2s in bytes. + BlockSize = 64 + + // The hash size of BLAKE2s-256 in bytes. + Size = 32 + + // The hash size of BLAKE2s-128 in bytes. + Size128 = 16 +) + +var errKeySize = errors.New("blake2s: invalid key size") + +var iv = [8]uint32{ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, +} + +// Sum256 returns the BLAKE2s-256 checksum of the data. +func Sum256(data []byte) [Size]byte { + var sum [Size]byte + checkSum(&sum, Size, data) + return sum +} + +// New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil +// key turns the hash into a MAC. The key must between zero and 32 bytes long. +// When the key is nil, the returned hash.Hash implements BinaryMarshaler +// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. +func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) } + +// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a +// non-empty key. Note that a 128-bit digest is too small to be secure as a +// cryptographic hash and should only be used as a MAC, thus the key argument +// is not optional. +func New128(key []byte) (hash.Hash, error) { + if len(key) == 0 { + return nil, errors.New("blake2s: a key is required for a 128-bit hash") + } + return newDigest(Size128, key) +} + +func newDigest(hashSize int, key []byte) (*digest, error) { + if len(key) > Size { + return nil, errKeySize + } + d := &digest{ + size: hashSize, + keyLen: len(key), + } + copy(d.key[:], key) + d.Reset() + return d, nil +} + +func checkSum(sum *[Size]byte, hashSize int, data []byte) { + var ( + h [8]uint32 + c [2]uint32 + ) + + h = iv + h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24) + + if length := len(data); length > BlockSize { + n := length &^ (BlockSize - 1) + if length == n { + n -= BlockSize + } + hashBlocks(&h, &c, 0, data[:n]) + data = data[n:] + } + + var block [BlockSize]byte + offset := copy(block[:], data) + remaining := uint32(BlockSize - offset) + + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + hashBlocks(&h, &c, 0xFFFFFFFF, block[:]) + + for i, v := range h { + binary.LittleEndian.PutUint32(sum[4*i:], v) + } +} + +type digest struct { + h [8]uint32 + c [2]uint32 + size int + block [BlockSize]byte + offset int + + key [BlockSize]byte + keyLen int +} + +const ( + magic = "b2s" + marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + if d.keyLen != 0 { + return nil, errors.New("crypto/blake2s: cannot marshal MACs") + } + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + for i := 0; i < 8; i++ { + b = appendUint32(b, d.h[i]) + } + b = appendUint32(b, d.c[0]) + b = appendUint32(b, d.c[1]) + // Maximum value for size is 32 + b = append(b, byte(d.size)) + b = append(b, d.block[:]...) + b = append(b, byte(d.offset)) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("crypto/blake2s: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/blake2s: invalid hash state size") + } + b = b[len(magic):] + for i := 0; i < 8; i++ { + b, d.h[i] = consumeUint32(b) + } + b, d.c[0] = consumeUint32(b) + b, d.c[1] = consumeUint32(b) + d.size = int(b[0]) + b = b[1:] + copy(d.block[:], b[:BlockSize]) + b = b[BlockSize:] + d.offset = int(b[0]) + return nil +} + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Size() int { return d.size } + +func (d *digest) Reset() { + d.h = iv + d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24) + d.offset, d.c[0], d.c[1] = 0, 0, 0 + if d.keyLen > 0 { + d.block = d.key + d.offset = BlockSize + } +} + +func (d *digest) Write(p []byte) (n int, err error) { + n = len(p) + + if d.offset > 0 { + remaining := BlockSize - d.offset + if n <= remaining { + d.offset += copy(d.block[d.offset:], p) + return + } + copy(d.block[d.offset:], p[:remaining]) + hashBlocks(&d.h, &d.c, 0, d.block[:]) + d.offset = 0 + p = p[remaining:] + } + + if length := len(p); length > BlockSize { + nn := length &^ (BlockSize - 1) + if length == nn { + nn -= BlockSize + } + hashBlocks(&d.h, &d.c, 0, p[:nn]) + p = p[nn:] + } + + d.offset += copy(d.block[:], p) + return +} + +func (d *digest) Sum(sum []byte) []byte { + var hash [Size]byte + d.finalize(&hash) + return append(sum, hash[:d.size]...) +} + +func (d *digest) finalize(hash *[Size]byte) { + var block [BlockSize]byte + h := d.h + c := d.c + + copy(block[:], d.block[:d.offset]) + remaining := uint32(BlockSize - d.offset) + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + hashBlocks(&h, &c, 0xFFFFFFFF, block[:]) + for i, v := range h { + binary.LittleEndian.PutUint32(hash[4*i:], v) + } +} + +func appendUint32(b []byte, x uint32) []byte { + var a [4]byte + binary.BigEndian.PutUint32(a[:], x) + return append(b, a[:]...) +} + +func consumeUint32(b []byte) ([]byte, uint32) { + x := binary.BigEndian.Uint32(b) + return b[4:], x +} diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_386.go b/vendor/golang.org/x/crypto/blake2s/blake2s_386.go new file mode 100644 index 00000000000..b4463fb4dc0 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_386.go @@ -0,0 +1,33 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build 386 && gc && !purego +// +build 386,gc,!purego + +package blake2s + +import "golang.org/x/sys/cpu" + +var ( + useSSE4 = false + useSSSE3 = cpu.X86.HasSSSE3 + useSSE2 = cpu.X86.HasSSE2 +) + +//go:noescape +func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) + +//go:noescape +func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) + +func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) { + switch { + case useSSSE3: + hashBlocksSSSE3(h, c, flag, blocks) + case useSSE2: + hashBlocksSSE2(h, c, flag, blocks) + default: + hashBlocksGeneric(h, c, flag, blocks) + } +} diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_386.s b/vendor/golang.org/x/crypto/blake2s/blake2s_386.s new file mode 100644 index 00000000000..603d00ca320 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_386.s @@ -0,0 +1,430 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build 386 && gc && !purego +// +build 386,gc,!purego + +#include "textflag.h" + +DATA iv0<>+0x00(SB)/4, $0x6a09e667 +DATA iv0<>+0x04(SB)/4, $0xbb67ae85 +DATA iv0<>+0x08(SB)/4, $0x3c6ef372 +DATA iv0<>+0x0c(SB)/4, $0xa54ff53a +GLOBL iv0<>(SB), (NOPTR+RODATA), $16 + +DATA iv1<>+0x00(SB)/4, $0x510e527f +DATA iv1<>+0x04(SB)/4, $0x9b05688c +DATA iv1<>+0x08(SB)/4, $0x1f83d9ab +DATA iv1<>+0x0c(SB)/4, $0x5be0cd19 +GLOBL iv1<>(SB), (NOPTR+RODATA), $16 + +DATA rol16<>+0x00(SB)/8, $0x0504070601000302 +DATA rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A +GLOBL rol16<>(SB), (NOPTR+RODATA), $16 + +DATA rol8<>+0x00(SB)/8, $0x0407060500030201 +DATA rol8<>+0x08(SB)/8, $0x0C0F0E0D080B0A09 +GLOBL rol8<>(SB), (NOPTR+RODATA), $16 + +DATA counter<>+0x00(SB)/8, $0x40 +DATA counter<>+0x08(SB)/8, $0x0 +GLOBL counter<>(SB), (NOPTR+RODATA), $16 + +#define ROTL_SSE2(n, t, v) \ + MOVO v, t; \ + PSLLL $n, t; \ + PSRLL $(32-n), v; \ + PXOR t, v + +#define ROTL_SSSE3(c, v) \ + PSHUFB c, v + +#define ROUND_SSE2(v0, v1, v2, v3, m0, m1, m2, m3, t) \ + PADDL m0, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(16, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m1, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(24, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v1, v1; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v3, v3; \ + PADDL m2, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(16, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m3, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(24, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v3, v3; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v1, v1 + +#define ROUND_SSSE3(v0, v1, v2, v3, m0, m1, m2, m3, t, c16, c8) \ + PADDL m0, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c16, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m1, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c8, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v1, v1; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v3, v3; \ + PADDL m2, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c16, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m3, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c8, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v3, v3; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v1, v1 + +#define PRECOMPUTE(dst, off, src, t) \ + MOVL 0*4(src), t; \ + MOVL t, 0*4+off+0(dst); \ + MOVL t, 9*4+off+64(dst); \ + MOVL t, 5*4+off+128(dst); \ + MOVL t, 14*4+off+192(dst); \ + MOVL t, 4*4+off+256(dst); \ + MOVL t, 2*4+off+320(dst); \ + MOVL t, 8*4+off+384(dst); \ + MOVL t, 12*4+off+448(dst); \ + MOVL t, 3*4+off+512(dst); \ + MOVL t, 15*4+off+576(dst); \ + MOVL 1*4(src), t; \ + MOVL t, 4*4+off+0(dst); \ + MOVL t, 8*4+off+64(dst); \ + MOVL t, 14*4+off+128(dst); \ + MOVL t, 5*4+off+192(dst); \ + MOVL t, 12*4+off+256(dst); \ + MOVL t, 11*4+off+320(dst); \ + MOVL t, 1*4+off+384(dst); \ + MOVL t, 6*4+off+448(dst); \ + MOVL t, 10*4+off+512(dst); \ + MOVL t, 3*4+off+576(dst); \ + MOVL 2*4(src), t; \ + MOVL t, 1*4+off+0(dst); \ + MOVL t, 13*4+off+64(dst); \ + MOVL t, 6*4+off+128(dst); \ + MOVL t, 8*4+off+192(dst); \ + MOVL t, 2*4+off+256(dst); \ + MOVL t, 0*4+off+320(dst); \ + MOVL t, 14*4+off+384(dst); \ + MOVL t, 11*4+off+448(dst); \ + MOVL t, 12*4+off+512(dst); \ + MOVL t, 4*4+off+576(dst); \ + MOVL 3*4(src), t; \ + MOVL t, 5*4+off+0(dst); \ + MOVL t, 15*4+off+64(dst); \ + MOVL t, 9*4+off+128(dst); \ + MOVL t, 1*4+off+192(dst); \ + MOVL t, 11*4+off+256(dst); \ + MOVL t, 7*4+off+320(dst); \ + MOVL t, 13*4+off+384(dst); \ + MOVL t, 3*4+off+448(dst); \ + MOVL t, 6*4+off+512(dst); \ + MOVL t, 10*4+off+576(dst); \ + MOVL 4*4(src), t; \ + MOVL t, 2*4+off+0(dst); \ + MOVL t, 1*4+off+64(dst); \ + MOVL t, 15*4+off+128(dst); \ + MOVL t, 10*4+off+192(dst); \ + MOVL t, 6*4+off+256(dst); \ + MOVL t, 8*4+off+320(dst); \ + MOVL t, 3*4+off+384(dst); \ + MOVL t, 13*4+off+448(dst); \ + MOVL t, 14*4+off+512(dst); \ + MOVL t, 5*4+off+576(dst); \ + MOVL 5*4(src), t; \ + MOVL t, 6*4+off+0(dst); \ + MOVL t, 11*4+off+64(dst); \ + MOVL t, 2*4+off+128(dst); \ + MOVL t, 9*4+off+192(dst); \ + MOVL t, 1*4+off+256(dst); \ + MOVL t, 13*4+off+320(dst); \ + MOVL t, 4*4+off+384(dst); \ + MOVL t, 8*4+off+448(dst); \ + MOVL t, 15*4+off+512(dst); \ + MOVL t, 7*4+off+576(dst); \ + MOVL 6*4(src), t; \ + MOVL t, 3*4+off+0(dst); \ + MOVL t, 7*4+off+64(dst); \ + MOVL t, 13*4+off+128(dst); \ + MOVL t, 12*4+off+192(dst); \ + MOVL t, 10*4+off+256(dst); \ + MOVL t, 1*4+off+320(dst); \ + MOVL t, 9*4+off+384(dst); \ + MOVL t, 14*4+off+448(dst); \ + MOVL t, 0*4+off+512(dst); \ + MOVL t, 6*4+off+576(dst); \ + MOVL 7*4(src), t; \ + MOVL t, 7*4+off+0(dst); \ + MOVL t, 14*4+off+64(dst); \ + MOVL t, 10*4+off+128(dst); \ + MOVL t, 0*4+off+192(dst); \ + MOVL t, 5*4+off+256(dst); \ + MOVL t, 9*4+off+320(dst); \ + MOVL t, 12*4+off+384(dst); \ + MOVL t, 1*4+off+448(dst); \ + MOVL t, 13*4+off+512(dst); \ + MOVL t, 2*4+off+576(dst); \ + MOVL 8*4(src), t; \ + MOVL t, 8*4+off+0(dst); \ + MOVL t, 5*4+off+64(dst); \ + MOVL t, 4*4+off+128(dst); \ + MOVL t, 15*4+off+192(dst); \ + MOVL t, 14*4+off+256(dst); \ + MOVL t, 3*4+off+320(dst); \ + MOVL t, 11*4+off+384(dst); \ + MOVL t, 10*4+off+448(dst); \ + MOVL t, 7*4+off+512(dst); \ + MOVL t, 1*4+off+576(dst); \ + MOVL 9*4(src), t; \ + MOVL t, 12*4+off+0(dst); \ + MOVL t, 2*4+off+64(dst); \ + MOVL t, 11*4+off+128(dst); \ + MOVL t, 4*4+off+192(dst); \ + MOVL t, 0*4+off+256(dst); \ + MOVL t, 15*4+off+320(dst); \ + MOVL t, 10*4+off+384(dst); \ + MOVL t, 7*4+off+448(dst); \ + MOVL t, 5*4+off+512(dst); \ + MOVL t, 9*4+off+576(dst); \ + MOVL 10*4(src), t; \ + MOVL t, 9*4+off+0(dst); \ + MOVL t, 4*4+off+64(dst); \ + MOVL t, 8*4+off+128(dst); \ + MOVL t, 13*4+off+192(dst); \ + MOVL t, 3*4+off+256(dst); \ + MOVL t, 5*4+off+320(dst); \ + MOVL t, 7*4+off+384(dst); \ + MOVL t, 15*4+off+448(dst); \ + MOVL t, 11*4+off+512(dst); \ + MOVL t, 0*4+off+576(dst); \ + MOVL 11*4(src), t; \ + MOVL t, 13*4+off+0(dst); \ + MOVL t, 10*4+off+64(dst); \ + MOVL t, 0*4+off+128(dst); \ + MOVL t, 3*4+off+192(dst); \ + MOVL t, 9*4+off+256(dst); \ + MOVL t, 6*4+off+320(dst); \ + MOVL t, 15*4+off+384(dst); \ + MOVL t, 4*4+off+448(dst); \ + MOVL t, 2*4+off+512(dst); \ + MOVL t, 12*4+off+576(dst); \ + MOVL 12*4(src), t; \ + MOVL t, 10*4+off+0(dst); \ + MOVL t, 12*4+off+64(dst); \ + MOVL t, 1*4+off+128(dst); \ + MOVL t, 6*4+off+192(dst); \ + MOVL t, 13*4+off+256(dst); \ + MOVL t, 4*4+off+320(dst); \ + MOVL t, 0*4+off+384(dst); \ + MOVL t, 2*4+off+448(dst); \ + MOVL t, 8*4+off+512(dst); \ + MOVL t, 14*4+off+576(dst); \ + MOVL 13*4(src), t; \ + MOVL t, 14*4+off+0(dst); \ + MOVL t, 3*4+off+64(dst); \ + MOVL t, 7*4+off+128(dst); \ + MOVL t, 2*4+off+192(dst); \ + MOVL t, 15*4+off+256(dst); \ + MOVL t, 12*4+off+320(dst); \ + MOVL t, 6*4+off+384(dst); \ + MOVL t, 0*4+off+448(dst); \ + MOVL t, 9*4+off+512(dst); \ + MOVL t, 11*4+off+576(dst); \ + MOVL 14*4(src), t; \ + MOVL t, 11*4+off+0(dst); \ + MOVL t, 0*4+off+64(dst); \ + MOVL t, 12*4+off+128(dst); \ + MOVL t, 7*4+off+192(dst); \ + MOVL t, 8*4+off+256(dst); \ + MOVL t, 14*4+off+320(dst); \ + MOVL t, 2*4+off+384(dst); \ + MOVL t, 5*4+off+448(dst); \ + MOVL t, 1*4+off+512(dst); \ + MOVL t, 13*4+off+576(dst); \ + MOVL 15*4(src), t; \ + MOVL t, 15*4+off+0(dst); \ + MOVL t, 6*4+off+64(dst); \ + MOVL t, 3*4+off+128(dst); \ + MOVL t, 11*4+off+192(dst); \ + MOVL t, 7*4+off+256(dst); \ + MOVL t, 10*4+off+320(dst); \ + MOVL t, 5*4+off+384(dst); \ + MOVL t, 9*4+off+448(dst); \ + MOVL t, 4*4+off+512(dst); \ + MOVL t, 8*4+off+576(dst) + +// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) +TEXT ·hashBlocksSSE2(SB), 0, $672-24 // frame = 656 + 16 byte alignment + MOVL h+0(FP), AX + MOVL c+4(FP), BX + MOVL flag+8(FP), CX + MOVL blocks_base+12(FP), SI + MOVL blocks_len+16(FP), DX + + MOVL SP, DI + ADDL $15, DI + ANDL $~15, DI + + MOVL CX, 8(DI) + MOVL 0(BX), CX + MOVL CX, 0(DI) + MOVL 4(BX), CX + MOVL CX, 4(DI) + XORL CX, CX + MOVL CX, 12(DI) + + MOVOU 0(AX), X0 + MOVOU 16(AX), X1 + MOVOU counter<>(SB), X2 + +loop: + MOVO X0, X4 + MOVO X1, X5 + MOVOU iv0<>(SB), X6 + MOVOU iv1<>(SB), X7 + + MOVO 0(DI), X3 + PADDQ X2, X3 + PXOR X3, X7 + MOVO X3, 0(DI) + + PRECOMPUTE(DI, 16, SI, CX) + ROUND_SSE2(X4, X5, X6, X7, 16(DI), 32(DI), 48(DI), 64(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+64(DI), 32+64(DI), 48+64(DI), 64+64(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+128(DI), 32+128(DI), 48+128(DI), 64+128(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+192(DI), 32+192(DI), 48+192(DI), 64+192(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+256(DI), 32+256(DI), 48+256(DI), 64+256(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+320(DI), 32+320(DI), 48+320(DI), 64+320(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+384(DI), 32+384(DI), 48+384(DI), 64+384(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+448(DI), 32+448(DI), 48+448(DI), 64+448(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+512(DI), 32+512(DI), 48+512(DI), 64+512(DI), X3) + ROUND_SSE2(X4, X5, X6, X7, 16+576(DI), 32+576(DI), 48+576(DI), 64+576(DI), X3) + + PXOR X4, X0 + PXOR X5, X1 + PXOR X6, X0 + PXOR X7, X1 + + LEAL 64(SI), SI + SUBL $64, DX + JNE loop + + MOVL 0(DI), CX + MOVL CX, 0(BX) + MOVL 4(DI), CX + MOVL CX, 4(BX) + + MOVOU X0, 0(AX) + MOVOU X1, 16(AX) + + RET + +// func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) +TEXT ·hashBlocksSSSE3(SB), 0, $704-24 // frame = 688 + 16 byte alignment + MOVL h+0(FP), AX + MOVL c+4(FP), BX + MOVL flag+8(FP), CX + MOVL blocks_base+12(FP), SI + MOVL blocks_len+16(FP), DX + + MOVL SP, DI + ADDL $15, DI + ANDL $~15, DI + + MOVL CX, 8(DI) + MOVL 0(BX), CX + MOVL CX, 0(DI) + MOVL 4(BX), CX + MOVL CX, 4(DI) + XORL CX, CX + MOVL CX, 12(DI) + + MOVOU 0(AX), X0 + MOVOU 16(AX), X1 + MOVOU counter<>(SB), X2 + +loop: + MOVO X0, 656(DI) + MOVO X1, 672(DI) + MOVO X0, X4 + MOVO X1, X5 + MOVOU iv0<>(SB), X6 + MOVOU iv1<>(SB), X7 + + MOVO 0(DI), X3 + PADDQ X2, X3 + PXOR X3, X7 + MOVO X3, 0(DI) + + MOVOU rol16<>(SB), X0 + MOVOU rol8<>(SB), X1 + + PRECOMPUTE(DI, 16, SI, CX) + ROUND_SSSE3(X4, X5, X6, X7, 16(DI), 32(DI), 48(DI), 64(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+64(DI), 32+64(DI), 48+64(DI), 64+64(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+128(DI), 32+128(DI), 48+128(DI), 64+128(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+192(DI), 32+192(DI), 48+192(DI), 64+192(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+256(DI), 32+256(DI), 48+256(DI), 64+256(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+320(DI), 32+320(DI), 48+320(DI), 64+320(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+384(DI), 32+384(DI), 48+384(DI), 64+384(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+448(DI), 32+448(DI), 48+448(DI), 64+448(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+512(DI), 32+512(DI), 48+512(DI), 64+512(DI), X3, X0, X1) + ROUND_SSSE3(X4, X5, X6, X7, 16+576(DI), 32+576(DI), 48+576(DI), 64+576(DI), X3, X0, X1) + + MOVO 656(DI), X0 + MOVO 672(DI), X1 + PXOR X4, X0 + PXOR X5, X1 + PXOR X6, X0 + PXOR X7, X1 + + LEAL 64(SI), SI + SUBL $64, DX + JNE loop + + MOVL 0(DI), CX + MOVL CX, 0(BX) + MOVL 4(DI), CX + MOVL CX, 4(BX) + + MOVOU X0, 0(AX) + MOVOU X1, 16(AX) + + RET diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go new file mode 100644 index 00000000000..becdaa120ff --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go @@ -0,0 +1,38 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && gc && !purego +// +build amd64,gc,!purego + +package blake2s + +import "golang.org/x/sys/cpu" + +var ( + useSSE4 = cpu.X86.HasSSE41 + useSSSE3 = cpu.X86.HasSSSE3 + useSSE2 = cpu.X86.HasSSE2 +) + +//go:noescape +func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) + +//go:noescape +func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) + +//go:noescape +func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) + +func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) { + switch { + case useSSE4: + hashBlocksSSE4(h, c, flag, blocks) + case useSSSE3: + hashBlocksSSSE3(h, c, flag, blocks) + case useSSE2: + hashBlocksSSE2(h, c, flag, blocks) + default: + hashBlocksGeneric(h, c, flag, blocks) + } +} diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s new file mode 100644 index 00000000000..e9df7a7c219 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s @@ -0,0 +1,433 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && gc && !purego +// +build amd64,gc,!purego + +#include "textflag.h" + +DATA iv0<>+0x00(SB)/4, $0x6a09e667 +DATA iv0<>+0x04(SB)/4, $0xbb67ae85 +DATA iv0<>+0x08(SB)/4, $0x3c6ef372 +DATA iv0<>+0x0c(SB)/4, $0xa54ff53a +GLOBL iv0<>(SB), (NOPTR+RODATA), $16 + +DATA iv1<>+0x00(SB)/4, $0x510e527f +DATA iv1<>+0x04(SB)/4, $0x9b05688c +DATA iv1<>+0x08(SB)/4, $0x1f83d9ab +DATA iv1<>+0x0c(SB)/4, $0x5be0cd19 +GLOBL iv1<>(SB), (NOPTR+RODATA), $16 + +DATA rol16<>+0x00(SB)/8, $0x0504070601000302 +DATA rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A +GLOBL rol16<>(SB), (NOPTR+RODATA), $16 + +DATA rol8<>+0x00(SB)/8, $0x0407060500030201 +DATA rol8<>+0x08(SB)/8, $0x0C0F0E0D080B0A09 +GLOBL rol8<>(SB), (NOPTR+RODATA), $16 + +DATA counter<>+0x00(SB)/8, $0x40 +DATA counter<>+0x08(SB)/8, $0x0 +GLOBL counter<>(SB), (NOPTR+RODATA), $16 + +#define ROTL_SSE2(n, t, v) \ + MOVO v, t; \ + PSLLL $n, t; \ + PSRLL $(32-n), v; \ + PXOR t, v + +#define ROTL_SSSE3(c, v) \ + PSHUFB c, v + +#define ROUND_SSE2(v0, v1, v2, v3, m0, m1, m2, m3, t) \ + PADDL m0, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(16, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m1, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(24, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v1, v1; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v3, v3; \ + PADDL m2, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(16, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m3, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSE2(24, t, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v3, v3; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v1, v1 + +#define ROUND_SSSE3(v0, v1, v2, v3, m0, m1, m2, m3, t, c16, c8) \ + PADDL m0, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c16, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m1, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c8, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v1, v1; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v3, v3; \ + PADDL m2, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c16, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(20, t, v1); \ + PADDL m3, v0; \ + PADDL v1, v0; \ + PXOR v0, v3; \ + ROTL_SSSE3(c8, v3); \ + PADDL v3, v2; \ + PXOR v2, v1; \ + ROTL_SSE2(25, t, v1); \ + PSHUFL $0x39, v3, v3; \ + PSHUFL $0x4E, v2, v2; \ + PSHUFL $0x93, v1, v1 + + +#define LOAD_MSG_SSE4(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) \ + MOVL i0*4(src), m0; \ + PINSRD $1, i1*4(src), m0; \ + PINSRD $2, i2*4(src), m0; \ + PINSRD $3, i3*4(src), m0; \ + MOVL i4*4(src), m1; \ + PINSRD $1, i5*4(src), m1; \ + PINSRD $2, i6*4(src), m1; \ + PINSRD $3, i7*4(src), m1; \ + MOVL i8*4(src), m2; \ + PINSRD $1, i9*4(src), m2; \ + PINSRD $2, i10*4(src), m2; \ + PINSRD $3, i11*4(src), m2; \ + MOVL i12*4(src), m3; \ + PINSRD $1, i13*4(src), m3; \ + PINSRD $2, i14*4(src), m3; \ + PINSRD $3, i15*4(src), m3 + +#define PRECOMPUTE_MSG(dst, off, src, R8, R9, R10, R11, R12, R13, R14, R15) \ + MOVQ 0*4(src), R8; \ + MOVQ 2*4(src), R9; \ + MOVQ 4*4(src), R10; \ + MOVQ 6*4(src), R11; \ + MOVQ 8*4(src), R12; \ + MOVQ 10*4(src), R13; \ + MOVQ 12*4(src), R14; \ + MOVQ 14*4(src), R15; \ + \ + MOVL R8, 0*4+off+0(dst); \ + MOVL R8, 9*4+off+64(dst); \ + MOVL R8, 5*4+off+128(dst); \ + MOVL R8, 14*4+off+192(dst); \ + MOVL R8, 4*4+off+256(dst); \ + MOVL R8, 2*4+off+320(dst); \ + MOVL R8, 8*4+off+384(dst); \ + MOVL R8, 12*4+off+448(dst); \ + MOVL R8, 3*4+off+512(dst); \ + MOVL R8, 15*4+off+576(dst); \ + SHRQ $32, R8; \ + MOVL R8, 4*4+off+0(dst); \ + MOVL R8, 8*4+off+64(dst); \ + MOVL R8, 14*4+off+128(dst); \ + MOVL R8, 5*4+off+192(dst); \ + MOVL R8, 12*4+off+256(dst); \ + MOVL R8, 11*4+off+320(dst); \ + MOVL R8, 1*4+off+384(dst); \ + MOVL R8, 6*4+off+448(dst); \ + MOVL R8, 10*4+off+512(dst); \ + MOVL R8, 3*4+off+576(dst); \ + \ + MOVL R9, 1*4+off+0(dst); \ + MOVL R9, 13*4+off+64(dst); \ + MOVL R9, 6*4+off+128(dst); \ + MOVL R9, 8*4+off+192(dst); \ + MOVL R9, 2*4+off+256(dst); \ + MOVL R9, 0*4+off+320(dst); \ + MOVL R9, 14*4+off+384(dst); \ + MOVL R9, 11*4+off+448(dst); \ + MOVL R9, 12*4+off+512(dst); \ + MOVL R9, 4*4+off+576(dst); \ + SHRQ $32, R9; \ + MOVL R9, 5*4+off+0(dst); \ + MOVL R9, 15*4+off+64(dst); \ + MOVL R9, 9*4+off+128(dst); \ + MOVL R9, 1*4+off+192(dst); \ + MOVL R9, 11*4+off+256(dst); \ + MOVL R9, 7*4+off+320(dst); \ + MOVL R9, 13*4+off+384(dst); \ + MOVL R9, 3*4+off+448(dst); \ + MOVL R9, 6*4+off+512(dst); \ + MOVL R9, 10*4+off+576(dst); \ + \ + MOVL R10, 2*4+off+0(dst); \ + MOVL R10, 1*4+off+64(dst); \ + MOVL R10, 15*4+off+128(dst); \ + MOVL R10, 10*4+off+192(dst); \ + MOVL R10, 6*4+off+256(dst); \ + MOVL R10, 8*4+off+320(dst); \ + MOVL R10, 3*4+off+384(dst); \ + MOVL R10, 13*4+off+448(dst); \ + MOVL R10, 14*4+off+512(dst); \ + MOVL R10, 5*4+off+576(dst); \ + SHRQ $32, R10; \ + MOVL R10, 6*4+off+0(dst); \ + MOVL R10, 11*4+off+64(dst); \ + MOVL R10, 2*4+off+128(dst); \ + MOVL R10, 9*4+off+192(dst); \ + MOVL R10, 1*4+off+256(dst); \ + MOVL R10, 13*4+off+320(dst); \ + MOVL R10, 4*4+off+384(dst); \ + MOVL R10, 8*4+off+448(dst); \ + MOVL R10, 15*4+off+512(dst); \ + MOVL R10, 7*4+off+576(dst); \ + \ + MOVL R11, 3*4+off+0(dst); \ + MOVL R11, 7*4+off+64(dst); \ + MOVL R11, 13*4+off+128(dst); \ + MOVL R11, 12*4+off+192(dst); \ + MOVL R11, 10*4+off+256(dst); \ + MOVL R11, 1*4+off+320(dst); \ + MOVL R11, 9*4+off+384(dst); \ + MOVL R11, 14*4+off+448(dst); \ + MOVL R11, 0*4+off+512(dst); \ + MOVL R11, 6*4+off+576(dst); \ + SHRQ $32, R11; \ + MOVL R11, 7*4+off+0(dst); \ + MOVL R11, 14*4+off+64(dst); \ + MOVL R11, 10*4+off+128(dst); \ + MOVL R11, 0*4+off+192(dst); \ + MOVL R11, 5*4+off+256(dst); \ + MOVL R11, 9*4+off+320(dst); \ + MOVL R11, 12*4+off+384(dst); \ + MOVL R11, 1*4+off+448(dst); \ + MOVL R11, 13*4+off+512(dst); \ + MOVL R11, 2*4+off+576(dst); \ + \ + MOVL R12, 8*4+off+0(dst); \ + MOVL R12, 5*4+off+64(dst); \ + MOVL R12, 4*4+off+128(dst); \ + MOVL R12, 15*4+off+192(dst); \ + MOVL R12, 14*4+off+256(dst); \ + MOVL R12, 3*4+off+320(dst); \ + MOVL R12, 11*4+off+384(dst); \ + MOVL R12, 10*4+off+448(dst); \ + MOVL R12, 7*4+off+512(dst); \ + MOVL R12, 1*4+off+576(dst); \ + SHRQ $32, R12; \ + MOVL R12, 12*4+off+0(dst); \ + MOVL R12, 2*4+off+64(dst); \ + MOVL R12, 11*4+off+128(dst); \ + MOVL R12, 4*4+off+192(dst); \ + MOVL R12, 0*4+off+256(dst); \ + MOVL R12, 15*4+off+320(dst); \ + MOVL R12, 10*4+off+384(dst); \ + MOVL R12, 7*4+off+448(dst); \ + MOVL R12, 5*4+off+512(dst); \ + MOVL R12, 9*4+off+576(dst); \ + \ + MOVL R13, 9*4+off+0(dst); \ + MOVL R13, 4*4+off+64(dst); \ + MOVL R13, 8*4+off+128(dst); \ + MOVL R13, 13*4+off+192(dst); \ + MOVL R13, 3*4+off+256(dst); \ + MOVL R13, 5*4+off+320(dst); \ + MOVL R13, 7*4+off+384(dst); \ + MOVL R13, 15*4+off+448(dst); \ + MOVL R13, 11*4+off+512(dst); \ + MOVL R13, 0*4+off+576(dst); \ + SHRQ $32, R13; \ + MOVL R13, 13*4+off+0(dst); \ + MOVL R13, 10*4+off+64(dst); \ + MOVL R13, 0*4+off+128(dst); \ + MOVL R13, 3*4+off+192(dst); \ + MOVL R13, 9*4+off+256(dst); \ + MOVL R13, 6*4+off+320(dst); \ + MOVL R13, 15*4+off+384(dst); \ + MOVL R13, 4*4+off+448(dst); \ + MOVL R13, 2*4+off+512(dst); \ + MOVL R13, 12*4+off+576(dst); \ + \ + MOVL R14, 10*4+off+0(dst); \ + MOVL R14, 12*4+off+64(dst); \ + MOVL R14, 1*4+off+128(dst); \ + MOVL R14, 6*4+off+192(dst); \ + MOVL R14, 13*4+off+256(dst); \ + MOVL R14, 4*4+off+320(dst); \ + MOVL R14, 0*4+off+384(dst); \ + MOVL R14, 2*4+off+448(dst); \ + MOVL R14, 8*4+off+512(dst); \ + MOVL R14, 14*4+off+576(dst); \ + SHRQ $32, R14; \ + MOVL R14, 14*4+off+0(dst); \ + MOVL R14, 3*4+off+64(dst); \ + MOVL R14, 7*4+off+128(dst); \ + MOVL R14, 2*4+off+192(dst); \ + MOVL R14, 15*4+off+256(dst); \ + MOVL R14, 12*4+off+320(dst); \ + MOVL R14, 6*4+off+384(dst); \ + MOVL R14, 0*4+off+448(dst); \ + MOVL R14, 9*4+off+512(dst); \ + MOVL R14, 11*4+off+576(dst); \ + \ + MOVL R15, 11*4+off+0(dst); \ + MOVL R15, 0*4+off+64(dst); \ + MOVL R15, 12*4+off+128(dst); \ + MOVL R15, 7*4+off+192(dst); \ + MOVL R15, 8*4+off+256(dst); \ + MOVL R15, 14*4+off+320(dst); \ + MOVL R15, 2*4+off+384(dst); \ + MOVL R15, 5*4+off+448(dst); \ + MOVL R15, 1*4+off+512(dst); \ + MOVL R15, 13*4+off+576(dst); \ + SHRQ $32, R15; \ + MOVL R15, 15*4+off+0(dst); \ + MOVL R15, 6*4+off+64(dst); \ + MOVL R15, 3*4+off+128(dst); \ + MOVL R15, 11*4+off+192(dst); \ + MOVL R15, 7*4+off+256(dst); \ + MOVL R15, 10*4+off+320(dst); \ + MOVL R15, 5*4+off+384(dst); \ + MOVL R15, 9*4+off+448(dst); \ + MOVL R15, 4*4+off+512(dst); \ + MOVL R15, 8*4+off+576(dst) + +#define BLAKE2s_SSE2() \ + PRECOMPUTE_MSG(BP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15); \ + ROUND_SSE2(X4, X5, X6, X7, 16(BP), 32(BP), 48(BP), 64(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+64(BP), 32+64(BP), 48+64(BP), 64+64(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+128(BP), 32+128(BP), 48+128(BP), 64+128(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+192(BP), 32+192(BP), 48+192(BP), 64+192(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+256(BP), 32+256(BP), 48+256(BP), 64+256(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+320(BP), 32+320(BP), 48+320(BP), 64+320(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+384(BP), 32+384(BP), 48+384(BP), 64+384(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+448(BP), 32+448(BP), 48+448(BP), 64+448(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+512(BP), 32+512(BP), 48+512(BP), 64+512(BP), X8); \ + ROUND_SSE2(X4, X5, X6, X7, 16+576(BP), 32+576(BP), 48+576(BP), 64+576(BP), X8) + +#define BLAKE2s_SSSE3() \ + PRECOMPUTE_MSG(BP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15); \ + ROUND_SSSE3(X4, X5, X6, X7, 16(BP), 32(BP), 48(BP), 64(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+64(BP), 32+64(BP), 48+64(BP), 64+64(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+128(BP), 32+128(BP), 48+128(BP), 64+128(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+192(BP), 32+192(BP), 48+192(BP), 64+192(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+256(BP), 32+256(BP), 48+256(BP), 64+256(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+320(BP), 32+320(BP), 48+320(BP), 64+320(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+384(BP), 32+384(BP), 48+384(BP), 64+384(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+448(BP), 32+448(BP), 48+448(BP), 64+448(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+512(BP), 32+512(BP), 48+512(BP), 64+512(BP), X8, X13, X14); \ + ROUND_SSSE3(X4, X5, X6, X7, 16+576(BP), 32+576(BP), 48+576(BP), 64+576(BP), X8, X13, X14) + +#define BLAKE2s_SSE4() \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ + LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0); \ + ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14) + +#define HASH_BLOCKS(h, c, flag, blocks_base, blocks_len, BLAKE2s_FUNC) \ + MOVQ h, AX; \ + MOVQ c, BX; \ + MOVL flag, CX; \ + MOVQ blocks_base, SI; \ + MOVQ blocks_len, DX; \ + \ + MOVQ SP, BP; \ + ADDQ $15, BP; \ + ANDQ $~15, BP; \ + \ + MOVQ 0(BX), R9; \ + MOVQ R9, 0(BP); \ + MOVQ CX, 8(BP); \ + \ + MOVOU 0(AX), X0; \ + MOVOU 16(AX), X1; \ + MOVOU iv0<>(SB), X2; \ + MOVOU iv1<>(SB), X3 \ + \ + MOVOU counter<>(SB), X12; \ + MOVOU rol16<>(SB), X13; \ + MOVOU rol8<>(SB), X14; \ + MOVO 0(BP), X15; \ + \ + loop: \ + MOVO X0, X4; \ + MOVO X1, X5; \ + MOVO X2, X6; \ + MOVO X3, X7; \ + \ + PADDQ X12, X15; \ + PXOR X15, X7; \ + \ + BLAKE2s_FUNC(); \ + \ + PXOR X4, X0; \ + PXOR X5, X1; \ + PXOR X6, X0; \ + PXOR X7, X1; \ + \ + LEAQ 64(SI), SI; \ + SUBQ $64, DX; \ + JNE loop; \ + \ + MOVO X15, 0(BP); \ + MOVQ 0(BP), R9; \ + MOVQ R9, 0(BX); \ + \ + MOVOU X0, 0(AX); \ + MOVOU X1, 16(AX) + +// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) +TEXT ·hashBlocksSSE2(SB), 0, $672-48 // frame = 656 + 16 byte alignment + HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE2) + RET + +// func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) +TEXT ·hashBlocksSSSE3(SB), 0, $672-48 // frame = 656 + 16 byte alignment + HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSSE3) + RET + +// func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) +TEXT ·hashBlocksSSE4(SB), 0, $32-48 // frame = 16 + 16 byte alignment + HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE4) + RET diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_generic.go b/vendor/golang.org/x/crypto/blake2s/blake2s_generic.go new file mode 100644 index 00000000000..24a1ff22adc --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_generic.go @@ -0,0 +1,178 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2s + +import ( + "math/bits" +) + +// the precomputed values for BLAKE2s +// there are 10 16-byte arrays - one for each round +// the entries are calculated from the sigma constants. +var precomputed = [10][16]byte{ + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, + {11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4}, + {7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8}, + {9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13}, + {2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9}, + {12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11}, + {13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10}, + {6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5}, + {10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0}, +} + +func hashBlocksGeneric(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) { + var m [16]uint32 + c0, c1 := c[0], c[1] + + for i := 0; i < len(blocks); { + c0 += BlockSize + if c0 < BlockSize { + c1++ + } + + v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7] + v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7] + v12 ^= c0 + v13 ^= c1 + v14 ^= flag + + for j := range m { + m[j] = uint32(blocks[i]) | uint32(blocks[i+1])<<8 | uint32(blocks[i+2])<<16 | uint32(blocks[i+3])<<24 + i += 4 + } + + for k := range precomputed { + s := &(precomputed[k]) + + v0 += m[s[0]] + v0 += v4 + v12 ^= v0 + v12 = bits.RotateLeft32(v12, -16) + v8 += v12 + v4 ^= v8 + v4 = bits.RotateLeft32(v4, -12) + v1 += m[s[1]] + v1 += v5 + v13 ^= v1 + v13 = bits.RotateLeft32(v13, -16) + v9 += v13 + v5 ^= v9 + v5 = bits.RotateLeft32(v5, -12) + v2 += m[s[2]] + v2 += v6 + v14 ^= v2 + v14 = bits.RotateLeft32(v14, -16) + v10 += v14 + v6 ^= v10 + v6 = bits.RotateLeft32(v6, -12) + v3 += m[s[3]] + v3 += v7 + v15 ^= v3 + v15 = bits.RotateLeft32(v15, -16) + v11 += v15 + v7 ^= v11 + v7 = bits.RotateLeft32(v7, -12) + + v0 += m[s[4]] + v0 += v4 + v12 ^= v0 + v12 = bits.RotateLeft32(v12, -8) + v8 += v12 + v4 ^= v8 + v4 = bits.RotateLeft32(v4, -7) + v1 += m[s[5]] + v1 += v5 + v13 ^= v1 + v13 = bits.RotateLeft32(v13, -8) + v9 += v13 + v5 ^= v9 + v5 = bits.RotateLeft32(v5, -7) + v2 += m[s[6]] + v2 += v6 + v14 ^= v2 + v14 = bits.RotateLeft32(v14, -8) + v10 += v14 + v6 ^= v10 + v6 = bits.RotateLeft32(v6, -7) + v3 += m[s[7]] + v3 += v7 + v15 ^= v3 + v15 = bits.RotateLeft32(v15, -8) + v11 += v15 + v7 ^= v11 + v7 = bits.RotateLeft32(v7, -7) + + v0 += m[s[8]] + v0 += v5 + v15 ^= v0 + v15 = bits.RotateLeft32(v15, -16) + v10 += v15 + v5 ^= v10 + v5 = bits.RotateLeft32(v5, -12) + v1 += m[s[9]] + v1 += v6 + v12 ^= v1 + v12 = bits.RotateLeft32(v12, -16) + v11 += v12 + v6 ^= v11 + v6 = bits.RotateLeft32(v6, -12) + v2 += m[s[10]] + v2 += v7 + v13 ^= v2 + v13 = bits.RotateLeft32(v13, -16) + v8 += v13 + v7 ^= v8 + v7 = bits.RotateLeft32(v7, -12) + v3 += m[s[11]] + v3 += v4 + v14 ^= v3 + v14 = bits.RotateLeft32(v14, -16) + v9 += v14 + v4 ^= v9 + v4 = bits.RotateLeft32(v4, -12) + + v0 += m[s[12]] + v0 += v5 + v15 ^= v0 + v15 = bits.RotateLeft32(v15, -8) + v10 += v15 + v5 ^= v10 + v5 = bits.RotateLeft32(v5, -7) + v1 += m[s[13]] + v1 += v6 + v12 ^= v1 + v12 = bits.RotateLeft32(v12, -8) + v11 += v12 + v6 ^= v11 + v6 = bits.RotateLeft32(v6, -7) + v2 += m[s[14]] + v2 += v7 + v13 ^= v2 + v13 = bits.RotateLeft32(v13, -8) + v8 += v13 + v7 ^= v8 + v7 = bits.RotateLeft32(v7, -7) + v3 += m[s[15]] + v3 += v4 + v14 ^= v3 + v14 = bits.RotateLeft32(v14, -8) + v9 += v14 + v4 ^= v9 + v4 = bits.RotateLeft32(v4, -7) + } + + h[0] ^= v0 ^ v8 + h[1] ^= v1 ^ v9 + h[2] ^= v2 ^ v10 + h[3] ^= v3 ^ v11 + h[4] ^= v4 ^ v12 + h[5] ^= v5 ^ v13 + h[6] ^= v6 ^ v14 + h[7] ^= v7 ^ v15 + } + c[0], c[1] = c0, c1 +} diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_ref.go b/vendor/golang.org/x/crypto/blake2s/blake2s_ref.go new file mode 100644 index 00000000000..799dba0c415 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_ref.go @@ -0,0 +1,18 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!amd64 && !386) || !gc || purego +// +build !amd64,!386 !gc purego + +package blake2s + +var ( + useSSE4 = false + useSSSE3 = false + useSSE2 = false +) + +func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) { + hashBlocksGeneric(h, c, flag, blocks) +} diff --git a/vendor/golang.org/x/crypto/blake2s/blake2x.go b/vendor/golang.org/x/crypto/blake2s/blake2x.go new file mode 100644 index 00000000000..828749ff01d --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/blake2x.go @@ -0,0 +1,178 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2s + +import ( + "encoding/binary" + "errors" + "io" +) + +// XOF defines the interface to hash functions that +// support arbitrary-length output. +type XOF interface { + // Write absorbs more data into the hash's state. It panics if called + // after Read. + io.Writer + + // Read reads more output from the hash. It returns io.EOF if the limit + // has been reached. + io.Reader + + // Clone returns a copy of the XOF in its current state. + Clone() XOF + + // Reset resets the XOF to its initial state. + Reset() +} + +// OutputLengthUnknown can be used as the size argument to NewXOF to indicate +// the length of the output is not known in advance. +const OutputLengthUnknown = 0 + +// magicUnknownOutputLength is a magic value for the output size that indicates +// an unknown number of output bytes. +const magicUnknownOutputLength = 65535 + +// maxOutputLength is the absolute maximum number of bytes to produce when the +// number of output bytes is unknown. +const maxOutputLength = (1 << 32) * 32 + +// NewXOF creates a new variable-output-length hash. The hash either produce a +// known number of bytes (1 <= size < 65535), or an unknown number of bytes +// (size == OutputLengthUnknown). In the latter case, an absolute limit of +// 128GiB applies. +// +// A non-nil key turns the hash into a MAC. The key must between +// zero and 32 bytes long. +func NewXOF(size uint16, key []byte) (XOF, error) { + if len(key) > Size { + return nil, errKeySize + } + if size == magicUnknownOutputLength { + // 2^16-1 indicates an unknown number of bytes and thus isn't a + // valid length. + return nil, errors.New("blake2s: XOF length too large") + } + if size == OutputLengthUnknown { + size = magicUnknownOutputLength + } + x := &xof{ + d: digest{ + size: Size, + keyLen: len(key), + }, + length: size, + } + copy(x.d.key[:], key) + x.Reset() + return x, nil +} + +type xof struct { + d digest + length uint16 + remaining uint64 + cfg, root, block [Size]byte + offset int + nodeOffset uint32 + readMode bool +} + +func (x *xof) Write(p []byte) (n int, err error) { + if x.readMode { + panic("blake2s: write to XOF after read") + } + return x.d.Write(p) +} + +func (x *xof) Clone() XOF { + clone := *x + return &clone +} + +func (x *xof) Reset() { + x.cfg[0] = byte(Size) + binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length + binary.LittleEndian.PutUint16(x.cfg[12:], x.length) // XOF length + x.cfg[15] = byte(Size) // inner hash size + + x.d.Reset() + x.d.h[3] ^= uint32(x.length) + + x.remaining = uint64(x.length) + if x.remaining == magicUnknownOutputLength { + x.remaining = maxOutputLength + } + x.offset, x.nodeOffset = 0, 0 + x.readMode = false +} + +func (x *xof) Read(p []byte) (n int, err error) { + if !x.readMode { + x.d.finalize(&x.root) + x.readMode = true + } + + if x.remaining == 0 { + return 0, io.EOF + } + + n = len(p) + if uint64(n) > x.remaining { + n = int(x.remaining) + p = p[:n] + } + + if x.offset > 0 { + blockRemaining := Size - x.offset + if n < blockRemaining { + x.offset += copy(p, x.block[x.offset:]) + x.remaining -= uint64(n) + return + } + copy(p, x.block[x.offset:]) + p = p[blockRemaining:] + x.offset = 0 + x.remaining -= uint64(blockRemaining) + } + + for len(p) >= Size { + binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) + x.nodeOffset++ + + x.d.initConfig(&x.cfg) + x.d.Write(x.root[:]) + x.d.finalize(&x.block) + + copy(p, x.block[:]) + p = p[Size:] + x.remaining -= uint64(Size) + } + + if todo := len(p); todo > 0 { + if x.remaining < uint64(Size) { + x.cfg[0] = byte(x.remaining) + } + binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) + x.nodeOffset++ + + x.d.initConfig(&x.cfg) + x.d.Write(x.root[:]) + x.d.finalize(&x.block) + + x.offset = copy(p, x.block[:todo]) + x.remaining -= uint64(todo) + } + + return +} + +func (d *digest) initConfig(cfg *[Size]byte) { + d.offset, d.c[0], d.c[1] = 0, 0, 0 + for i := range d.h { + d.h[i] = iv[i] ^ binary.LittleEndian.Uint32(cfg[i*4:]) + } +} diff --git a/vendor/golang.org/x/crypto/blake2s/register.go b/vendor/golang.org/x/crypto/blake2s/register.go new file mode 100644 index 00000000000..ef79ff3c67a --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2s/register.go @@ -0,0 +1,22 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.9 +// +build go1.9 + +package blake2s + +import ( + "crypto" + "hash" +) + +func init() { + newHash256 := func() hash.Hash { + h, _ := New256(nil) + return h + } + + crypto.RegisterHash(crypto.BLAKE2s_256, newHash256) +} diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go new file mode 100644 index 00000000000..cf3eeb158a9 --- /dev/null +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go @@ -0,0 +1,124 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package ripemd160 implements the RIPEMD-160 hash algorithm. +// +// Deprecated: RIPEMD-160 is a legacy hash and should not be used for new +// applications. Also, this package does not and will not provide an optimized +// implementation. Instead, use a modern hash like SHA-256 (from crypto/sha256). +package ripemd160 // import "golang.org/x/crypto/ripemd160" + +// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart +// Preneel with specifications available at: +// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf. + +import ( + "crypto" + "hash" +) + +func init() { + crypto.RegisterHash(crypto.RIPEMD160, New) +} + +// The size of the checksum in bytes. +const Size = 20 + +// The block size of the hash algorithm in bytes. +const BlockSize = 64 + +const ( + _s0 = 0x67452301 + _s1 = 0xefcdab89 + _s2 = 0x98badcfe + _s3 = 0x10325476 + _s4 = 0xc3d2e1f0 +) + +// digest represents the partial evaluation of a checksum. +type digest struct { + s [5]uint32 // running context + x [BlockSize]byte // temporary buffer + nx int // index into x + tc uint64 // total count of bytes processed +} + +func (d *digest) Reset() { + d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4 + d.nx = 0 + d.tc = 0 +} + +// New returns a new hash.Hash computing the checksum. +func New() hash.Hash { + result := new(digest) + result.Reset() + return result +} + +func (d *digest) Size() int { return Size } + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + d.tc += uint64(nn) + if d.nx > 0 { + n := len(p) + if n > BlockSize-d.nx { + n = BlockSize - d.nx + } + for i := 0; i < n; i++ { + d.x[d.nx+i] = p[i] + } + d.nx += n + if d.nx == BlockSize { + _Block(d, d.x[0:]) + d.nx = 0 + } + p = p[n:] + } + n := _Block(d, p) + p = p[n:] + if len(p) > 0 { + d.nx = copy(d.x[:], p) + } + return +} + +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + + // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. + tc := d.tc + var tmp [64]byte + tmp[0] = 0x80 + if tc%64 < 56 { + d.Write(tmp[0 : 56-tc%64]) + } else { + d.Write(tmp[0 : 64+56-tc%64]) + } + + // Length in bits. + tc <<= 3 + for i := uint(0); i < 8; i++ { + tmp[i] = byte(tc >> (8 * i)) + } + d.Write(tmp[0:8]) + + if d.nx != 0 { + panic("d.nx != 0") + } + + var digest [Size]byte + for i, s := range d.s { + digest[i*4] = byte(s) + digest[i*4+1] = byte(s >> 8) + digest[i*4+2] = byte(s >> 16) + digest[i*4+3] = byte(s >> 24) + } + + return append(in, digest[:]...) +} diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go new file mode 100644 index 00000000000..e0edc02f0f3 --- /dev/null +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go @@ -0,0 +1,165 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// RIPEMD-160 block step. +// In its own file so that a faster assembly or C version +// can be substituted easily. + +package ripemd160 + +import ( + "math/bits" +) + +// work buffer indices and roll amounts for one line +var _n = [80]uint{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13, +} + +var _r = [80]uint{ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6, +} + +// same for the other parallel one +var n_ = [80]uint{ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11, +} + +var r_ = [80]uint{ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11, +} + +func _Block(md *digest, p []byte) int { + n := 0 + var x [16]uint32 + var alpha, beta uint32 + for len(p) >= BlockSize { + a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4] + aa, bb, cc, dd, ee := a, b, c, d, e + j := 0 + for i := 0; i < 16; i++ { + x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 + j += 4 + } + + // round 1 + i := 0 + for i < 16 { + alpha = a + (b ^ c ^ d) + x[_n[i]] + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 2 + for i < 32 { + alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 3 + for i < 48 { + alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 4 + for i < 64 { + alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 5 + for i < 80 { + alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb ^ cc ^ dd) + x[n_[i]] + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // combine results + dd += c + md.s[1] + md.s[1] = md.s[2] + d + ee + md.s[2] = md.s[3] + e + aa + md.s[3] = md.s[4] + a + bb + md.s[4] = md.s[0] + b + cc + md.s[0] = dd + + p = p[BlockSize:] + n += BlockSize + } + return n +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c769d2f347e..274f1a2bd73 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -13,7 +13,7 @@ cloud.google.com/go/iam/apiv1/iampb cloud.google.com/go/kms/apiv1 cloud.google.com/go/kms/apiv1/kmspb cloud.google.com/go/kms/internal -# code.gitea.io/sdk/gitea v0.15.1 +# code.gitea.io/sdk/gitea v0.16.0 ## explicit; go 1.13 code.gitea.io/sdk/gitea # contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d @@ -337,6 +337,9 @@ github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew +# github.com/davidmz/go-pageant v1.0.2 +## explicit; go 1.16 +github.com/davidmz/go-pageant # github.com/dimchansky/utfbom v1.1.1 ## explicit github.com/dimchansky/utfbom @@ -376,6 +379,9 @@ github.com/evanphx/json-patch github.com/evanphx/json-patch/v5 # github.com/fatih/color v1.13.0 ## explicit; go 1.13 +# github.com/go-fed/httpsig v1.1.0 +## explicit; go 1.13 +github.com/go-fed/httpsig # github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 ## explicit; go 1.13 github.com/go-git/gcfg @@ -959,6 +965,7 @@ go.uber.org/zap/zaptest ## explicit; go 1.17 golang.org/x/crypto/argon2 golang.org/x/crypto/blake2b +golang.org/x/crypto/blake2s golang.org/x/crypto/blowfish golang.org/x/crypto/cast5 golang.org/x/crypto/chacha20 @@ -976,6 +983,7 @@ golang.org/x/crypto/ocsp golang.org/x/crypto/pbkdf2 golang.org/x/crypto/pkcs12 golang.org/x/crypto/pkcs12/internal/rc2 +golang.org/x/crypto/ripemd160 golang.org/x/crypto/salsa20/salsa golang.org/x/crypto/scrypt golang.org/x/crypto/sha3