Skip to content
Merged
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
20 changes: 20 additions & 0 deletions pkg/api/signed_url.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import (
log "github.com/sirupsen/logrus"
)

var (
customDomainRegex = regexp.MustCompile(`https:\/\/[a-z0-9\-\.]+\/[a-z0-9\-]+\/[a-z0-9\-]+\/([^?]+)\?`)
)

type SignedURL struct {
URL string `json:"url,omitempty"`
Method string `json:"method,omitempty"`
Expand Down Expand Up @@ -221,6 +225,10 @@ func (u *SignedURL) GetObject() (string, error) {
log.Debugf("Parsing localhost URL: %s\n", u.URL)
return parseLocalhostURL(URL)

case customDomainRegex.Match([]byte(URL.String())):
log.Debugf("Parsing custom domain URL: %s\n", u.URL)
return parseCustomDomainURL(URL)

default:
log.Warnf("Failed to parse URL '%s' - unrecognized host '%s'\n", u.URL, host)
return "", fmt.Errorf("unrecognized host %s", host)
Expand Down Expand Up @@ -257,6 +265,18 @@ func parseS3URL(URL *url.URL) (string, error) {
return parsed[3], nil
}

// Custom domain URLs are used when minio or some other s3-compatible storage is being used.
// The URL will be of the form: https://<domain>/<bucket>/<semaphore-project-id>/<path>
// We are only interested in the <path> part here.
func parseCustomDomainURL(URL *url.URL) (string, error) {
parsed := customDomainRegex.FindStringSubmatch(URL.String())
if len(parsed) < 2 {
return "", fmt.Errorf("Failed to parse custom domain URL '%s'\n", URL)
}

return parsed[1], nil
}

// Localhost URLs are used during tests
func parseLocalhostURL(URL *url.URL) (string, error) {
// we don't want the leading slash
Expand Down
18 changes: 16 additions & 2 deletions pkg/api/signed_url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,22 @@ func Test__GetObject(t *testing.T) {
assert.Equal(t, "artifacts/project/projectid/mydir/myfile.txt", obj)
})

t.Run("bad host", func(t *testing.T) {
signedURL := SignedURL{URL: "https://somehost.com/projectid/artifacts/project/projectid/myfile.txt"}
t.Run("custom domain - file", func(t *testing.T) {
signedURL := SignedURL{URL: "https://artifacts.somedomain.com/my-bucket1/projectid/artifacts/project/projectid/myfile.txt?X-Amz-Algorithm"}
obj, err := signedURL.GetObject()
assert.Nil(t, err)
assert.Equal(t, "artifacts/project/projectid/myfile.txt", obj)
})

t.Run("custom domain - file inside directory", func(t *testing.T) {
signedURL := SignedURL{URL: "https://artifacts.somedomain.com/my-bucket1/projectid/artifacts/project/projectid/mydir/myfile.txt?Expires=231256754712"}
obj, err := signedURL.GetObject()
assert.Nil(t, err)
assert.Equal(t, "artifacts/project/projectid/mydir/myfile.txt", obj)
})

t.Run("bad URL", func(t *testing.T) {
signedURL := SignedURL{URL: "http://somehost.com/projectid/artifacts/project/projectid/myfile.txt"}
_, err := signedURL.GetObject()
assert.NotNil(t, err)
})
Expand Down