diff --git a/.github/workflows/golint.yaml b/.github/workflows/golint.yaml index bf3a6ade..6a94c863 100644 --- a/.github/workflows/golint.yaml +++ b/.github/workflows/golint.yaml @@ -20,4 +20,4 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v6.1.0 with: - args: -E bodyclose,gocritic,gofmt,gosec,govet,nestif,nlreturn,revive,rowserrcheck --exclude G401,G501,G107,G307 + args: -E bodyclose,gocritic,gofmt,gosec,govet,nestif,nlreturn,revive,rowserrcheck --exclude G401,G501,G107,G307,G115 diff --git a/README.md b/README.md index 6a562cce..fbb997f9 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,14 @@ Follow the dialogue to get authenticated and then click on `Download inbox s3cmd Alternatively, you can download the configuration file using the [login command](#Login). +The access token used to authenticate to the inbox can be supplied in 3 different ways; in the config file, as an ENV `ACCESSTOKEN` or on the command line `-accessToken ` as part of the upload command. + +The Priority order for the access token is: + +1. Using the `-accessToken` flag +2. From the ENV `ACCESSTOKEN` +3. In the config file + ### Upload file(s) Now that the configuration file is downloaded, the file(s) can be uploaded to the archive using the binary file created in the first step of this guide. To upload a specific file, use the following command: diff --git a/go.mod b/go.mod index 84a9cc7f..efc68cbd 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,10 @@ go 1.22.3 require ( github.com/aws/aws-sdk-go v1.55.5 + github.com/dustin/go-humanize v1.0.1 + github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743 + github.com/johannesboyne/gofakes3 v0.0.0-20220627085814-c3ac35da23b2 github.com/manifoldco/promptui v0.9.0 github.com/neicnordic/crypt4gh v1.12.0 github.com/sirupsen/logrus v1.9.3 @@ -17,9 +21,9 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect + github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -32,10 +36,3 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -require ( - github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect - github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743 - github.com/johannesboyne/gofakes3 v0.0.0-20220627085814-c3ac35da23b2 -) diff --git a/helpers/helpers.go b/helpers/helpers.go index 5f2151e4..d63dd73e 100644 --- a/helpers/helpers.go +++ b/helpers/helpers.go @@ -263,7 +263,7 @@ func LoadConfigFile(path string) (*Config, error) { return nil, err } - if config.AccessKey == "" || config.AccessToken == "" { + if config.AccessKey == "" { return nil, errors.New("failed to find credentials in configuration file") } diff --git a/upload/upload.go b/upload/upload.go index d9973c8c..5f465d12 100644 --- a/upload/upload.go +++ b/upload/upload.go @@ -25,7 +25,7 @@ import ( // Usage text that will be displayed as command line help text when using the // `help upload` command var Usage = ` -USAGE: %s upload -config (--encrypt-with-key ) (--force-overwrite) (--force-unencrypted) (-r) [file(s) | folder(s)] (-targetDir ) +USAGE: %s upload -config (-accessToken ) (--encrypt-with-key ) (--force-overwrite) (--force-unencrypted) (-r) [file(s) | folder(s)] (-targetDir ) upload: Uploads files to the Sensitive Data Archive (SDA). @@ -63,6 +63,8 @@ var pubKeyPath = Args.String("encrypt-with-key", "", "Only unencrypted data should be provided when this flag is set.", ) +var accessToken = Args.String("accessToken", "", "Access token to the inbox service.\n(optional, if it is set in the config file or exported as the ENV `ACCESSTOKEN`)") + // Function uploadFiles uploads the files in the input list to the s3 bucket func uploadFiles(files, outFiles []string, targetDir string, config *helpers.Config) error { // check also here in case sth went wrong with input files @@ -291,6 +293,15 @@ func Upload(args []string) error { return err } + switch { + case os.Getenv("ACCESSTOKEN") == "" && *accessToken == "" && config.AccessToken == "": + return errors.New("no access token supplied") + case os.Getenv("ACCESSTOKEN") != "" && *accessToken == "": + config.AccessToken = os.Getenv("ACCESSTOKEN") + case *accessToken != "": + config.AccessToken = *accessToken + } + err = helpers.CheckTokenExpiration(config.AccessToken) if err != nil { return err diff --git a/upload/upload_test.go b/upload/upload_test.go index 330bd0d5..f5b6f175 100644 --- a/upload/upload_test.go +++ b/upload/upload_test.go @@ -33,6 +33,8 @@ func TestConfigTestSuite(t *testing.T) { } func (suite *TestSuite) SetupTest() { + os.Setenv("ACCESSTOKEN", "") + *accessToken = "" suite.accessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleXN0b3JlLUNIQU5HRS1NRSJ9.eyJqdGkiOiJWTWpfNjhhcEMxR2FJbXRZdFExQ0ciLCJzdWIiOiJkdW1teSIsImlzcyI6Imh0dHA6Ly9vaWRjOjkwOTAiLCJpYXQiOjE3MDc3NjMyODksImV4cCI6MTg2NTU0NzkxOSwic2NvcGUiOiJvcGVuaWQgZ2E0Z2hfcGFzc3BvcnRfdjEgcHJvZmlsZSBlbWFpbCIsImF1ZCI6IlhDNTZFTDExeHgifQ.ZFfIAOGeM2I5cvqr1qJV74qU65appYjpNJVWevGHjGA5Xk_qoRMFJXmG6AiQnYdMKnJ58sYGNjWgs2_RGyw5NyM3-pgP7EKHdWU4PrDOU84Kosg4IPMSFxbBRAEjR5X04YX_CLYW2MFk_OyM9TIln522_JBVT_jA5WTTHSmBRHntVArYYHvQdF-oFRiqL8JXWlsUBh3tqQ33sZdqd9g64YhTk9a5lEC42gn5Hg9Hm_qvkl5orzEqIg7x9z5706IBE4Zypco5ohrAKsEbA8EKbEBb0jigGgCslQNde2owUyKIkvZYmxHA78X5xpymMp9K--PgbkyMS9GtA-YwOHPs-w" } @@ -312,6 +314,49 @@ func (suite *TestSuite) TestFunctionality() { newArgs = []string{"upload", "-config", configPath.Name(), "--encrypt-with-key", "somekey", testfile.Name()} assert.EqualError(suite.T(), Upload(newArgs), "aborting") + // config file without an access_token + var confFileNoToken = fmt.Sprintf(` + host_base = %[1]s + encoding = UTF-8 + host_bucket = %[1]s + multipart_chunk_size_mb = 50 + secret_key = dummy + access_key = dummy + use_https = False + check_ssl_certificate = False + check_ssl_hostname = False + socket_timeout = 30 + human_readable_sizes = True + guess_mime_type = True + encrypt = False + `, strings.TrimPrefix(ts.URL, "http://")) + + err = os.WriteFile(configPath.Name(), []byte(confFileNoToken), 0600) + if err != nil { + suite.FailNow("failed to write temp config file, %v", err) + } + + // Check that an access token is supplied + newArgs = []string{"upload", "-config", configPath.Name(), testfile.Name()} + assert.EqualError(suite.T(), Upload(newArgs), "no access token supplied") + + os.Setenv("ACCESSTOKEN", "BadToken") + // Supplying an accesstoken as a ENV overrules the one in the config file + newArgs = []string{"upload", "-config", configPath.Name(), testfile.Name()} + assert.EqualError(suite.T(), Upload(newArgs), "could not parse token, reason: token contains an invalid number of segments") + + suite.SetupTest() + os.Setenv("ACCESSTOKEN", suite.accessToken) + newArgs = []string{"upload", "-config", configPath.Name(), testfile.Name()} + assert.NoError(suite.T(), Upload(newArgs)) + + // Supplying an accesstoken as a parameter overrules the one in the config file + newArgs = []string{"upload", "-accessToken", "BadToken", "-config", configPath.Name(), testfile.Name()} + assert.EqualError(suite.T(), Upload(newArgs), "could not parse token, reason: token contains an invalid number of segments") + + newArgs = []string{"upload", "-accessToken", suite.accessToken, "-config", configPath.Name(), testfile.Name()} + assert.NoError(suite.T(), Upload(newArgs)) + // Remove hash files created by Encrypt if err := os.Remove("checksum_encrypted.md5"); err != nil { log.Panic(err)