Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions pkg/artifacts/artifacts_v4.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,28 @@ func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, tas
func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID int64) string {
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
uploadURL := "http://" + strings.TrimSuffix(r.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") +
"/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID)
"/" + endp + "?sig=" + base64.RawURLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID)
return uploadURL
}

func decodeBase64URLSignature(sig string) ([]byte, error) {
if decoded, err := base64.RawURLEncoding.DecodeString(sig); err == nil {
return decoded, nil
}
return base64.URLEncoding.DecodeString(sig)
}

func (r artifactV4Routes) verifySignature(ctx *ArtifactContext, endp string) (int64, string, bool) {
rawTaskID := ctx.Req.URL.Query().Get("taskID")
sig := ctx.Req.URL.Query().Get("sig")
expires := ctx.Req.URL.Query().Get("expires")
artifactName := ctx.Req.URL.Query().Get("artifactName")
dsig, _ := base64.URLEncoding.DecodeString(sig)
dsig, err := decodeBase64URLSignature(sig)
if err != nil {
log.Error("Error unauthorized")
ctx.Error(http.StatusUnauthorized, "Error unauthorized")
return -1, "", false
}
taskID, _ := strconv.ParseInt(rawTaskID, 10, 64)

expecedsig := r.buildSignature(endp, expires, artifactName, taskID)
Expand Down
42 changes: 42 additions & 0 deletions pkg/artifacts/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -393,3 +394,44 @@ func TestArtifactUploadBlobUnsafePath(t *testing.T) {
assert.Equal("success", response.Message)
assert.Equal("content", string(memfs["artifact/server/path/1/some/file"].Data))
}

func TestArtifactV4BuildArtifactURLUsesRawBase64Signature(t *testing.T) {
assert := assert.New(t)

route := artifactV4Routes{
prefix: ArtifactV4RouteBase,
AppURL: "localhost",
}

uploadURL, err := url.Parse(route.buildArtifactURL("UploadArtifact", "test-artifact", 1))
assert.NoError(err)
assert.NotContains(uploadURL.Query().Get("sig"), "=")
}

func TestArtifactV4UploadAcceptsUnpaddedBase64Signature(t *testing.T) {
assert := assert.New(t)

var memfs = fstest.MapFS(map[string]*fstest.MapFile{})
route := artifactV4Routes{
fs: writeMapFS{memfs},
rfs: memfs,
baseDir: "artifact/server/path",
prefix: ArtifactV4RouteBase,
AppURL: "localhost",
}

uploadURL, err := url.Parse(route.buildArtifactURL("UploadArtifact", "test-artifact", 1))
assert.NoError(err)
query := uploadURL.Query()
query.Set("sig", strings.TrimRight(query.Get("sig"), "="))
query.Set("comp", "block")
uploadURL.RawQuery = query.Encode()

req, _ := http.NewRequest("PUT", uploadURL.String(), strings.NewReader("content"))
rr := httptest.NewRecorder()

route.uploadArtifact(&ArtifactContext{Req: req, Resp: rr})

assert.Equal(http.StatusCreated, rr.Code)
assert.Equal("content", string(memfs["artifact/server/path/1/test-artifact/test-artifact.zip"].Data))
}