diff --git a/README.md b/README.md index 0a2fe57..7521477 100644 --- a/README.md +++ b/README.md @@ -87,12 +87,13 @@ Flags: -H, --headers strings headers to send in request, can have multiple i.e -H 'content-type:application/json' -H' connection:close' -h, --help help for run --jwt-aud string JWT audience (aud) claim + --jwt-claims string JWT custom claims --jwt-header string JWT header field name --jwt-iss string JWT issuer (iss) claim --jwt-key string JWT signing private key path --jwt-kid string JWT KID --jwt-sub string JWT subject (sub) claim - --jwt-claims string JWT custom claims as a JSON string, ex: {"iat": 1719410063, "browser": "chrome"} + -f, --jwts-filename string File path for pre-generated JWTs, separated by new lines -m, --method string request method (default "GET") --mtls-cert string mTLS cert path --mtls-key string mTLS cert private key path @@ -221,6 +222,13 @@ https://github.com/domsolutions/gopayloader +-----------------------+-------------------------------+ ``` +If you have your own JWTs you want to test, you can supply a file to send the JWTs i.e. `./my-jwts.txt` where each jwt is separated by a new line. + +```shell +./gopayloader run http://localhost:8081 -c 1 -r 1000000 --jwt-header "my-jwt" -f ./my-jwts.txt +``` + + To remove all generated jwts; ```shell diff --git a/cmd/payloader/run.go b/cmd/payloader/run.go index ad7e5de..0f363be 100644 --- a/cmd/payloader/run.go +++ b/cmd/payloader/run.go @@ -9,29 +9,30 @@ import ( ) const ( - argMethod = "method" - argConnections = "connections" - argRequests = "requests" - argKeepAlive = "disable-keep-alive" - argVerifySigner = "skip-verify" - argTime = "time" - argMTLSKey = "mtls-key" - argMTLSCert = "mtls-cert" - argReadTimeout = "read-timeout" - argWriteTimeout = "write-timeout" - argVerbose = "verbose" - argTicker = "ticker" - argJWTKey = "jwt-key" - argJWTSUb = "jwt-sub" + argMethod = "method" + argConnections = "connections" + argRequests = "requests" + argKeepAlive = "disable-keep-alive" + argVerifySigner = "skip-verify" + argTime = "time" + argMTLSKey = "mtls-key" + argMTLSCert = "mtls-cert" + argReadTimeout = "read-timeout" + argWriteTimeout = "write-timeout" + argVerbose = "verbose" + argTicker = "ticker" + argJWTKey = "jwt-key" + argJWTSUb = "jwt-sub" argJWTCustomClaims = "jwt-claims" - argJWTIss = "jwt-iss" - argJWTAud = "jwt-aud" - argJWTHeader = "jwt-header" - argJWTKid = "jwt-kid" - argHeaders = "headers" - argBody = "body" - argBodyFile = "body-file" - argClient = "client" + argJWTIss = "jwt-iss" + argJWTAud = "jwt-aud" + argJWTHeader = "jwt-header" + argJWTKid = "jwt-kid" + argJWTsFilename = "jwts-filename" + argHeaders = "headers" + argBody = "body" + argBodyFile = "body-file" + argClient = "client" ) var ( @@ -55,6 +56,7 @@ var ( jwtAud string jwtHeader string jwtKID string + jwtsFilename string headers *[]string body string bodyFile string @@ -92,6 +94,7 @@ var runCmd = &cobra.Command{ jwtIss, jwtAud, jwtHeader, + jwtsFilename, *headers, body, bodyFile, @@ -128,11 +131,16 @@ func init() { runCmd.Flags().StringVar(&jwtIss, argJWTIss, "", "JWT issuer (iss) claim") runCmd.Flags().StringVar(&jwtSub, argJWTSUb, "", "JWT subject (sub) claim") runCmd.Flags().StringVar(&jwtCustomClaims, argJWTCustomClaims, "", "JWT custom claims") + runCmd.Flags().StringVarP(&jwtsFilename, argJWTsFilename, "f", "", "File path for pre-generated JWTs, separated by new lines") runCmd.Flags().StringVar(&jwtHeader, argJWTHeader, "", "JWT header field name") runCmd.MarkFlagsRequiredTogether(argMTLSCert, argMTLSKey) - runCmd.MarkFlagsRequiredTogether(argJWTKey, argJWTHeader) runCmd.MarkFlagsMutuallyExclusive(argBody, argBodyFile) - + runCmd.MarkFlagsMutuallyExclusive(argJWTsFilename, argJWTKid) + runCmd.MarkFlagsMutuallyExclusive(argJWTsFilename, argJWTAud) + runCmd.MarkFlagsMutuallyExclusive(argJWTsFilename, argJWTIss) + runCmd.MarkFlagsMutuallyExclusive(argJWTsFilename, argJWTCustomClaims) + runCmd.MarkFlagsMutuallyExclusive(argJWTsFilename, argJWTSUb) + runCmd.MarkFlagsMutuallyExclusive(argJWTsFilename, argJWTKey) rootCmd.AddCommand(runCmd) } diff --git a/cmd/payloader/test-server.go b/cmd/payloader/test-server.go index 4224fab..5d91a13 100644 --- a/cmd/payloader/test-server.go +++ b/cmd/payloader/test-server.go @@ -11,9 +11,11 @@ import ( "log" "net/http" "os" + "os/signal" "path/filepath" "strconv" "strings" + "syscall" "time" ) @@ -87,9 +89,25 @@ var runServerCmd = &cobra.Command{ }, } - if err := server.ListenAndServe(addr); err != nil { - return err + errs := make(chan error) + go func() { + if err := server.ListenAndServe(addr); err != nil { + log.Println(err) + errs <- err + } + }() + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + + select { + case <-c: + log.Println("User cancelled, shutting down") + server.Shutdown() + case err := <-errs: + log.Printf("Got error from server; %v \n", err) } + return nil } diff --git a/config/config.go b/config/config.go index 91ddc16..69e12c6 100644 --- a/config/config.go +++ b/config/config.go @@ -34,6 +34,7 @@ type Config struct { JwtIss string JwtAud string JwtHeader string + JwtsFilename string SendJWT bool Headers []string Body string @@ -41,7 +42,7 @@ type Config struct { Client string } -func NewConfig(ctx context.Context, reqURI, mTLScert, mTLSKey string, disableKeepAlive bool, reqs int64, conns uint, totalTime time.Duration, skipVerify bool, readTimeout, writeTimeout time.Duration, method string, verbose bool, ticker time.Duration, jwtKID, jwtKey, jwtSub, jwtCustomClaimsJSON, jwtIss, jwtAud, jwtHeader string, headers []string, body, bodyFile string, client string) *Config { +func NewConfig(ctx context.Context, reqURI, mTLScert, mTLSKey string, disableKeepAlive bool, reqs int64, conns uint, totalTime time.Duration, skipVerify bool, readTimeout, writeTimeout time.Duration, method string, verbose bool, ticker time.Duration, jwtKID, jwtKey, jwtSub, jwtCustomClaimsJSON, jwtIss, jwtAud, jwtHeader, jwtsFilename string, headers []string, body, bodyFile string, client string) *Config { return &Config{ Ctx: ctx, ReqURI: reqURI, @@ -64,6 +65,7 @@ func NewConfig(ctx context.Context, reqURI, mTLScert, mTLSKey string, disableKee JwtIss: jwtIss, JwtAud: jwtAud, JwtHeader: jwtHeader, + JwtsFilename: jwtsFilename, Headers: headers, Body: body, BodyFile: bodyFile, @@ -139,14 +141,14 @@ func (c *Config) Validate() error { } } - if (c.JwtHeader == "") != (c.JwtKey == "") { - if c.JwtHeader == "" { - return errors.New("config: empty jwt header") - } + // Require JwtHeader if JwtKey or JwtsFilename is present + if (c.JwtsFilename != "" || c.JwtKey != "") && c.JwtHeader == "" { + return errors.New("config: empty jwt header") + } - if c.JwtKey == "" { - return errors.New("empty jwt key") - } + // Require JwtKey or JwtsFilename if JwtHeader is present + if c.JwtHeader != "" && c.JwtsFilename == "" && c.JwtKey == "" { + return errors.New("config: empty jwt filename and jwt key, one of those is needed to send requests with JWTs") } if c.JwtKey != "" { @@ -163,6 +165,20 @@ func (c *Config) Validate() error { c.SendJWT = true } + if c.JwtsFilename != "" { + _, err := os.OpenFile(c.JwtsFilename, os.O_RDONLY, os.ModePerm) + if err != nil { + if os.IsNotExist(err) { + return errors.New("config: jwt file does not exist: " + c.JwtsFilename) + } + return fmt.Errorf("config: jwt file error checking file exists; %v", err) + } + if c.ReqTarget == 0 { + return errors.New("can only send jwts when request number is specified") + } + c.SendJWT = true + } + if len(c.Headers) > 0 { for _, h := range c.Headers { if !strings.Contains(h, ":") { diff --git a/pkgs/http-clients/definitions.go b/pkgs/http-clients/definitions.go index 57c9bed..75cffd9 100644 --- a/pkgs/http-clients/definitions.go +++ b/pkgs/http-clients/definitions.go @@ -41,7 +41,6 @@ type Config struct { Method string Verbose bool JwtStreamReceiver <-chan string - JwtStreamErr <-chan error JWTHeader string Headers []string Body string diff --git a/pkgs/jwt-generator/cache.go b/pkgs/jwt-generator/cache.go index 885ea8c..cf2935e 100644 --- a/pkgs/jwt-generator/cache.go +++ b/pkgs/jwt-generator/cache.go @@ -2,14 +2,17 @@ package jwt_generator import ( "bufio" - "encoding/binary" "errors" "fmt" + "github.com/pterm/pterm" "os" + "strconv" "strings" "time" ) +const byteSizeCounter = 20 + type cache struct { f *os.File count int64 @@ -20,14 +23,22 @@ func newCache(f *os.File) (*cache, error) { c := cache{f: f} c.scanner = bufio.NewScanner(c.f) + // Get count found on first line of the file c.scanner.Split(bufio.ScanLines) if c.scanner.Scan() { - bb := make([]byte, 8) + bb := make([]byte, byteSizeCounter) _, err := f.ReadAt(bb, 0) if err != nil { return nil, err } - c.count = int64(binary.LittleEndian.Uint64(bb)) + + count, err := getCount(bb) + if err != nil { + pterm.Error.Printf("Got error reading jwt count from cache; %v", err) + return nil, err + } + + c.count = count return &c, nil } return &c, nil @@ -37,6 +48,23 @@ func (c *cache) getJwtCount() int64 { return c.count } +func getCount(bb []byte) (int64, error) { + num := make([]byte, 0) + for _, m := range bb { + if m == 0 { + break + } + num = append(num, m) + } + + s := string(num) + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return 0, err + } + return i, nil +} + func (c *cache) get(count int64) (<-chan string, <-chan error) { recv := make(chan string, 1000000) errs := make(chan error, 1) @@ -61,14 +89,22 @@ func (c *cache) get(count int64) (<-chan string, <-chan error) { } meta := c.scanner.Bytes() - if len(meta) < 8 { + if len(meta) < byteSizeCounter { errs <- fmt.Errorf("jwt_generator: retrieving; corrupt jwt cache, wanted 8 bytes got %d", len(meta)) close(errs) close(recv) return recv, errs } - if count > int64(binary.LittleEndian.Uint64(meta[0:8])) { + i, err := getCount(meta) + if err != nil { + errs <- fmt.Errorf("failed to get jwt count; %v", err) + close(errs) + close(recv) + return recv, errs + } + + if count > i { errs <- errors.New("jwt_generator: retrieving; not enough jwts stored in cache") close(errs) close(recv) @@ -83,20 +119,25 @@ func (c *cache) get(count int64) (<-chan string, <-chan error) { func (c *cache) retrieve(count int64, recv chan<- string, errs chan<- error) { var i int64 = 0 + defer func() { + close(errs) + close(recv) + }() for i = 0; i < count; i++ { if c.scanner.Scan() { recv <- string(c.scanner.Bytes()) continue } - // reached EOF or err + if err := c.scanner.Err(); err != nil { errs <- err - close(errs) + return } - break + + errs <- errors.New("unable to read anymore jwts from file") + return } - close(recv) } func (c *cache) save(tokens []string) error { @@ -110,19 +151,25 @@ func (c *cache) save(tokens []string) error { if stat.Size() > 0 { pos = stat.Size() } + if _, err := c.f.WriteAt([]byte(strings.Join(tokens, "\n")+"\n"), pos); err != nil { return err } - b := make([]byte, 8) - newCount := uint64(int64(add) + c.count) - binary.LittleEndian.PutUint64(b, newCount) + newCount := int64(add) + c.count + s := strconv.FormatInt(newCount, 10) + + b := make([]byte, byteSizeCounter) + for i, ss := range s { + b[i] = byte(ss) + } + _, err = c.f.WriteAt(b, 0) if err != nil { return err } - _, err = c.f.WriteAt([]byte{byte('\n')}, 9) + _, err = c.f.WriteAt([]byte{byte('\n')}, byteSizeCounter) if err != nil { return err } diff --git a/pkgs/jwt-generator/jwt.go b/pkgs/jwt-generator/jwt.go index a1c8e1e..361a515 100644 --- a/pkgs/jwt-generator/jwt.go +++ b/pkgs/jwt-generator/jwt.go @@ -1,21 +1,22 @@ package jwt_generator import ( + "bufio" "context" "crypto/sha256" "encoding/hex" "errors" "fmt" - "strings" + config "github.com/domsolutions/gopayloader/config" jwt_signer "github.com/domsolutions/gopayloader/pkgs/jwt-signer" "github.com/domsolutions/gopayloader/pkgs/jwt-signer/definition" - config "github.com/domsolutions/gopayloader/config" "github.com/golang-jwt/jwt" "github.com/google/uuid" "github.com/pterm/pterm" "os" "path/filepath" "runtime" + "strings" "time" ) @@ -24,16 +25,17 @@ const ( ) type Config struct { - Ctx context.Context - Kid string - JwtKeyPath string - jwtKeyBlob []byte - JwtSub string + Ctx context.Context + Kid string + JwtKeyPath string + jwtKeyBlob []byte + JwtSub string JwtCustomClaimsJSON string - JwtIss string - JwtAud string - signer definition.Signer - store *cache + JwtIss string + JwtAud string + JwtsFilename string + signer definition.Signer + store *cache } type JWTGenerator struct { @@ -58,6 +60,59 @@ func (c *Config) validate() error { return nil } +// GetUserSuppliedJWTs Gets a count number of JWTs from a file, reusing them if not enough exist to match count +func GetUserSuppliedJWTs(fname string, count int64) (<-chan string, <-chan error) { + recv := make(chan string, 1000000) + errs := make(chan error, 1) + go getUserJWTS(fname, count, errs, recv) + + // give goroutine time to prime channel with jwts for workers + time.Sleep(1 * time.Second) + return recv, errs +} + +func getUserJWTS(fname string, count int64, errs chan<- error, jwts chan<- string) { + defer func() { + close(errs) + close(jwts) + }() + + file, err := os.OpenFile(fname, os.O_RDONLY, os.ModePerm) + if err != nil { + errs <- fmt.Errorf("jwt_generator: retrieving; failed to open file containing JWTs; %v", err) + return + } + defer file.Close() + + jwtsSent := int64(0) + for jwtsSent < count { + // Set pointer to beginning of file + if _, err := file.Seek(0, 0); err != nil { + errs <- err + return + } + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + + fileValid := false + for scanner.Scan() { + fileValid = true + jwts <- string(scanner.Bytes()) + jwtsSent++ + // Stop reading file when enough JWTs have been fetched + if jwtsSent == count { + return + } + } + + if !fileValid { + errs <- fmt.Errorf("jwt_generator: retrieving; file doesn't contain a JWT") + return + } + // Loops if user asked for more requests than there were JWTs in the file, so JWTs get reused + } +} + func (j *JWTGenerator) getFileName(dir string) string { hash := sha256.New() hash.Write([]byte(j.config.JwtAud)) @@ -86,7 +141,7 @@ func (j *JWTGenerator) Generate(reqJwtCount int64, dir string, retrying bool) er return err } f.Close() - pterm.Debug.Printf("jwt cache %s file corrupt, attempting to delete and recreate; got error; %v \n", fname, err) + pterm.Error.Printf("jwt cache %s file corrupt, attempting to delete and recreate; got error; %v \n", fname, err) if err := os.Remove(fname); err != nil { pterm.Error.Printf("Couldn't remove cache file %s; %v", fname, err) return err diff --git a/pkgs/payloader/payloader.go b/pkgs/payloader/payloader.go index a78f9dd..275438b 100644 --- a/pkgs/payloader/payloader.go +++ b/pkgs/payloader/payloader.go @@ -89,7 +89,7 @@ func (p *PayLoader) startWorkers(wg *sync.WaitGroup) { } func (p *PayLoader) handleReqs() (*GoPayloaderResults, error) { - var jwtStreamErrs <-chan error + var jwtErr <-chan error var jwtStream <-chan string if p.config.SendJWT && p.config.ReqTarget != 0 { @@ -97,26 +97,31 @@ func (p *PayLoader) handleReqs() (*GoPayloaderResults, error) { pterm.Error.Println("Can't save jwts if no cache directory") return nil, errors.New("cache directory couldn't be determined") } - - pterm.Info.Printf("Sending jwts with requests, checking for jwts in cache\n") - - jwt := jwt_generator.NewJWTGenerator(&jwt_generator.Config{ - Ctx: p.config.Ctx, - Kid: p.config.JwtKID, - JwtKeyPath: p.config.JwtKey, - JwtSub: p.config.JwtSub, - JwtCustomClaimsJSON: p.config.JwtCustomClaimsJSON, - JwtIss: p.config.JwtIss, - JwtAud: p.config.JwtAud, - }) - if err := os.MkdirAll(JwtCacheDir, 0755); err != nil { return nil, err } - if err := jwt.Generate(p.config.ReqTarget, JwtCacheDir, false); err != nil { - return nil, err + + pterm.Info.Printf("Sending jwts with requests\n") + if p.config.JwtsFilename != "" { + pterm.Info.Printf("Using JWTs from %s \n", p.config.JwtsFilename) + jwtStream, jwtErr = jwt_generator.GetUserSuppliedJWTs(p.config.JwtsFilename, p.config.ReqTarget) + } else { + pterm.Info.Printf("Checking for JWTs in cache\n") + jwt := jwt_generator.NewJWTGenerator(&jwt_generator.Config{ + Ctx: p.config.Ctx, + Kid: p.config.JwtKID, + JwtKeyPath: p.config.JwtKey, + JwtSub: p.config.JwtSub, + JwtCustomClaimsJSON: p.config.JwtCustomClaimsJSON, + JwtIss: p.config.JwtIss, + JwtAud: p.config.JwtAud, + }) + + if err := jwt.Generate(p.config.ReqTarget, JwtCacheDir, false); err != nil { + return nil, err + } + jwtStream, jwtErr = jwt.JWTS(p.config.ReqTarget) } - jwtStream, jwtStreamErrs = jwt.JWTS(p.config.ReqTarget) } reqsPerWorker := p.config.ReqTarget / int64(p.config.Conns) @@ -181,7 +186,6 @@ func (p *PayLoader) handleReqs() (*GoPayloaderResults, error) { if p.config.SendJWT { c.JwtStreamReceiver = jwtStream - c.JwtStreamErr = jwtStreamErrs c.JWTHeader = p.config.JwtHeader } @@ -206,6 +210,14 @@ func (p *PayLoader) handleReqs() (*GoPayloaderResults, error) { results := &GoPayloaderResults{} go p.calcReqStats(ctx, reqStats, results) + if jwtErr != nil { + err, _ := <-jwtErr + if err != nil { + pterm.Error.Printf("Failed to retrieve JWTs; %v \n", err) + return nil, err + } + } + workersComplete.Wait() pterm.Success.Printf("Payload complete, calculating results\n") diff --git a/pkgs/payloader/payloader_test.go b/pkgs/payloader/payloader_test.go index 643c96f..f4be43f 100644 --- a/pkgs/payloader/payloader_test.go +++ b/pkgs/payloader/payloader_test.go @@ -348,6 +348,32 @@ func testPayLoader_Run(t *testing.T, addr, client string, cleanup func()) { } }, }, + { + name: "GET using JWT file only", + fields: fields{config: &config.Config{ + Ctx: context.Background(), + ReqURI: addr, + ReqTarget: 10, + Conns: 1, + ReadTimeout: 5 * time.Second, + WriteTimeout: 5 * time.Second, + Method: "GET", + Client: client, + VerboseTicker: time.Second, + Headers: []string{"content-type: application/json"}, + JwtHeader: "Authorization", + JwtsFilename: filepath.Join("..", "..", "test", "jwtstestfile.txt"), + SkipVerify: true, + }}, + want: &GoPayloaderResults{ + CompletedReqs: 10, + FailedReqs: 0, + Responses: map[worker.ResponseCode]int64{ + 200: 10, + }, + Errors: nil, + }, + }, { name: "Error hostname incorrect format - missing port", fields: fields{config: &config.Config{ diff --git a/pkgs/payloader/worker/generate.go b/pkgs/payloader/worker/generate.go index 087d76c..a3002fb 100644 --- a/pkgs/payloader/worker/generate.go +++ b/pkgs/payloader/worker/generate.go @@ -91,14 +91,7 @@ func getReq(client http_clients.GoPayLoaderClient, config *http_clients.Config) func jwtMiddleware(w *WorkerBase) { select { - case <-w.config.Ctx.Done(): - // user cancelled - return - //case err := <-w.config.JwtStreamErr: - // pterm.Error.Printf("Failed to get jwts from cache, got error; %v \n", err) - // return TODO fix case jwt := <-w.config.JwtStreamReceiver: - //fmt.Printf("GOT JWT %sHELP \n", jwt) w.req.SetHeader(w.config.JWTHeader, jwt) } } diff --git a/test/jwtstestfile.txt b/test/jwtstestfile.txt new file mode 100644 index 0000000..a5e9130 --- /dev/null +++ b/test/jwtstestfile.txt @@ -0,0 +1,5 @@ +eyJhbGciOiJSUzUxMiIsImtpZCI6IjEzMzI1NTc1dGV2ZGZiZHNmc2YiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJzb21lLWF1ZCIsImV4cCI6MTcxOTYwODQ3NCwiaXNzIjoic29tZS1pc3N1ZXIiLCJqdGkiOiI1ZWI2Y2I2NC1jNmIxLTRkZmEtYTVlZC0wYTQ0ZjI4ZTcyODMiLCJzdWIiOiJzb21lLXN1YmplY3QifQ.wDjfS7oIHIlBS2BvWq5HPt0u_eFYioVGT-wMgkqDvzEFBl1ElHy6h2WRVQqGg5jIU1_dKfiA5IwXrG-2Eilm40CKOGBVBXijaqgqtpSIirRi00zKfllMczkB8Mv4ZtAFquYCvqnfdM4fyAEklJtA0JI7mcMok06dzA5oLU2HGKM +eyJhbGciOiJSUzUxMiIsImtpZCI6IjEzMzI1NTc1dGV2ZGZiZHNmc2YiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJzb21lLWF1ZCIsImV4cCI6MTcxOTYwODQ3NCwiaXNzIjoic29tZS1pc3N1ZXIiLCJqdGkiOiJmN2E3MzI5Ny0yZDA2LTRlN2EtYmE4Yi03YjJjOTY3MGFkNmMiLCJzdWIiOiJzb21lLXN1YmplY3QifQ.K9qVL3dwi_TZNWSXNeWfXk91JTIZmm9Mp9Di09YMK_H9k7rO3qrpJtlBNuwe78QMZ9lhgGOW7ObUvvYdMqaHgLBBGqUEIHflOFcVUVx-pWdHJvq37pnNb5wX7fJQUqZkrpugC5kIk2Od3UKaCGBmHast5V3YF8LcBsd7fnufvEo +eyJhbGciOiJSUzUxMiIsImtpZCI6IjEzMzI1NTc1dGV2ZGZiZHNmc2YiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJzb21lLWF1ZCIsImV4cCI6MTcxOTYwODQ3NCwiaXNzIjoic29tZS1pc3N1ZXIiLCJqdGkiOiI1MzgwNGVlMy00M2E2LTQ4MGYtYmNkYS05ODAyNTE2MTUwYWMiLCJzdWIiOiJzb21lLXN1YmplY3QifQ.opl49eC3Dom-B5I3D8lqCnqyb_T3MmaS8nOjT6Wc83BBEFRxwEy2ZE4jSkv0cqeQ4-CfNHXHalsudZbyMRklZRDmK98VnBQUJBlrVQ2wRaRyv55CjQ06QG8E00fTOVQYgHH65JpqomBTkoFHwCCLYc88Epsz93Dlce7WHKr8KrE +eyJhbGciOiJSUzUxMiIsImtpZCI6IjEzMzI1NTc1dGV2ZGZiZHNmc2YiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJzb21lLWF1ZCIsImV4cCI6MTcxOTYwODQ3NCwiaXNzIjoic29tZS1pc3N1ZXIiLCJqdGkiOiJjMGE0ZWVlYS1hMzZiLTRlOTEtOWQ4NS1jYjAxZDg1MjI4MGMiLCJzdWIiOiJzb21lLXN1YmplY3QifQ.ScocLLUIo3d92h9sCdX36XC1LbOu8_lQXqzQfIN_6m-pwi4F-7cAr18QcPybgHIDv2x1NoGMX16iJclK0ntn6OG_IukCZJOiy3GyrLmM3YZNu0b66J394-n0-6CHw3HbM17-KqnYxAUERSaj6pgiLJBtl-XagPY-nZOThgVUDhM +eyJhbGciOiJSUzUxMiIsImtpZCI6IjEzMzI1NTc1dGV2ZGZiZHNmc2YiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJzb21lLWF1ZCIsImV4cCI6MTcxOTYwODQ3NCwiaXNzIjoic29tZS1pc3N1ZXIiLCJqdGkiOiJiMDBiODFmMS1kMGQzLTQ4ZGYtODQ5MC1iZDU5MGMzNWU2ZDQiLCJzdWIiOiJzb21lLXN1YmplY3QifQ.gN2XgYFOVsxvzanhYTlICvrreuSIIhOYGd3jffhVt1jRsisY_nmFj_JtN-pLAESkxBxZFnLvvk2QCUcscbMt80WCDH5MAkmVL3qqawQcqkSV2SnHrJ43gXxniuH2eL5EaQQUpW7a6UhVYWyGWECTE0MY5P1aA4lE_SidS5CXc1s diff --git a/version/version.go b/version/version.go index 77580b5..b8789ea 100644 --- a/version/version.go +++ b/version/version.go @@ -1,3 +1,3 @@ package version -const Version = "0.3.2" +const Version = "0.3.3" diff --git a/wrapper/wrapper.go b/wrapper/wrapper.go index 19659e2..31a211d 100644 --- a/wrapper/wrapper.go +++ b/wrapper/wrapper.go @@ -15,7 +15,7 @@ import ( "github.com/domsolutions/gopayloader/pkgs/payloader" ) -func RunGoPayLoader(reqURI, mTLScert, mTLSKey string, disableKeepAlive bool, reqs int64, conns uint, totalTime time.Duration, skipVerify bool, readTimeout, writeTimeout time.Duration, method string, verbose bool, ticker time.Duration, jwtKID, jwtKey, jwtSub, jwtCustomClaimsJSON, jwtIss, jwtAud, jwtHeader string, headers []string, body, bodyFile string, client string) error { +func RunGoPayLoader(reqURI, mTLScert, mTLSKey string, disableKeepAlive bool, reqs int64, conns uint, totalTime time.Duration, skipVerify bool, readTimeout, writeTimeout time.Duration, method string, verbose bool, ticker time.Duration, jwtKID, jwtKey, jwtSub, jwtCustomClaimsJSON, jwtIss, jwtAud, jwtHeader, jwtsFilename string, headers []string, body, bodyFile string, client string) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -33,7 +33,7 @@ func RunGoPayLoader(reqURI, mTLScert, mTLSKey string, disableKeepAlive bool, req method, verbose, ticker, - jwtKID, jwtKey, jwtSub, jwtCustomClaimsJSON, jwtIss, jwtAud, jwtHeader, headers, body, bodyFile, client) + jwtKID, jwtKey, jwtSub, jwtCustomClaimsJSON, jwtIss, jwtAud, jwtHeader, jwtsFilename, headers, body, bodyFile, client) if err := conf.Validate(); err != nil { return err }