jwtear 1.0.3 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e525a4137016b92472239033b86cc80e65ecd8fa75e77a0cc41c8639efbe8087
4
- data.tar.gz: f59b1ccf37571aafb5dbbab81513b95dffc4f1b0fcefd61a6ff4c963e164a17e
3
+ metadata.gz: 2681c86bec09d95803c8051feae4f7a647f2fda293425c5b01c25e8d7b97977b
4
+ data.tar.gz: 20db1a8f7aea19fe20e96d736e0df7b83626e73c9cf7df8e9033fbe55f9459ee
5
5
  SHA512:
6
- metadata.gz: bdf15b504417a7cf3fc8653938317b72efbf60b4cccff6096f1d25f19875110d972385ba8c3834c83ed704ddf651f580608c4e36a4b782e10ec9c9ac593762b6
7
- data.tar.gz: 9fae6f5523f4df145282221ac8021376c3dca4a061592ad431e6c7c7441700e3f337d03bc8074eebae5a3f8f841c9bbaad65a1774ddf32f8228c6cd113cd6f1c
6
+ metadata.gz: 20c40cce0192a37fc2924799597d584a891a192c81f31376f02edf24f944c22378eb253e799569fce6ea6e2926e7c15af3e5acb5672d6470f7e355f6179eb3f1
7
+ data.tar.gz: ca85ee1cb1b2a6a1ea6267b0a952bf5586fbf92d215069d5739d5642bf80a5456849be75ea9205869249a7cb4ee15fa94a109f4321a1dcb2cead8b790bf293bf
@@ -0,0 +1,30 @@
1
+ name: Push2RubyGems
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ build:
11
+ name: Build + Publish
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: Set up Ruby 2.6
17
+ uses: actions/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.6.x
20
+
21
+ - name: Publish to RubyGems
22
+ run: |
23
+ mkdir -p $HOME/.gem
24
+ touch $HOME/.gem/credentials
25
+ chmod 0600 $HOME/.gem/credentials
26
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
27
+ gem build *.gemspec
28
+ gem push *.gem
29
+ env:
30
+ GEM_HOST_API_KEY: "${{secrets.GEM_HOST_API_KEY}}"
data/Gemfile.lock CHANGED
@@ -1,71 +1,70 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jwtear (1.0.3)
5
- gli (~> 2.19, >= 2.19.0)
6
- json-jwt (~> 1.10, >= 1.10.2)
4
+ jwtear (1.0.7)
5
+ colorize (~> 0.8.1)
6
+ gli (~> 2.20, >= 2.20.0)
7
+ json-jwt (~> 1.13.0)
7
8
  jwe (~> 0.4.0)
8
- tty-markdown (~> 0.6.0)
9
- tty-pager (~> 0.12.1)
9
+ tty-markdown (~> 0.7.0)
10
+ tty-pager (~> 0.14.0)
10
11
 
11
12
  GEM
12
13
  remote: https://rubygems.org/
13
14
  specs:
14
- activesupport (6.0.0)
15
+ activesupport (6.1.4.1)
15
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
- i18n (>= 0.7, < 2)
17
- minitest (~> 5.1)
18
- tzinfo (~> 1.1)
19
- zeitwerk (~> 2.1, >= 2.1.8)
20
- aes_key_wrap (1.0.1)
21
- bindata (2.4.4)
22
- concurrent-ruby (1.1.5)
23
- equatable (0.6.1)
24
- gli (2.19.0)
25
- i18n (1.7.0)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
20
+ zeitwerk (~> 2.3)
21
+ aes_key_wrap (1.1.0)
22
+ bindata (2.4.10)
23
+ colorize (0.8.1)
24
+ concurrent-ruby (1.1.9)
25
+ gli (2.20.1)
26
+ i18n (1.8.10)
26
27
  concurrent-ruby (~> 1.0)
27
- json-jwt (1.10.2)
28
+ json-jwt (1.13.0)
28
29
  activesupport (>= 4.2)
29
30
  aes_key_wrap
30
31
  bindata
31
32
  jwe (0.4.0)
32
- kramdown (1.16.2)
33
- minitest (5.12.2)
34
- pastel (0.7.3)
35
- equatable (~> 0.6)
33
+ kramdown (2.3.1)
34
+ rexml
35
+ minitest (5.14.4)
36
+ pastel (0.8.0)
36
37
  tty-color (~> 0.5)
37
- rouge (3.11.1)
38
- strings (0.1.6)
39
- strings-ansi (~> 0.1)
40
- unicode-display_width (~> 1.5)
38
+ rexml (3.2.5)
39
+ rouge (3.26.0)
40
+ strings (0.2.1)
41
+ strings-ansi (~> 0.2)
42
+ unicode-display_width (>= 1.5, < 3.0)
41
43
  unicode_utils (~> 1.4)
42
- strings-ansi (0.1.0)
43
- thread_safe (0.3.6)
44
- tty-color (0.5.0)
45
- tty-markdown (0.6.0)
46
- kramdown (~> 1.16.2)
47
- pastel (~> 0.7.2)
48
- rouge (~> 3.3)
49
- strings (~> 0.1.4)
50
- tty-color (~> 0.4)
51
- tty-screen (~> 0.6)
52
- tty-pager (0.12.1)
53
- strings (~> 0.1.4)
54
- tty-screen (~> 0.6)
55
- tty-which (~> 0.4)
56
- tty-screen (0.7.0)
57
- tty-which (0.4.1)
58
- tzinfo (1.2.5)
59
- thread_safe (~> 0.1)
60
- unicode-display_width (1.6.0)
44
+ strings-ansi (0.2.0)
45
+ tty-color (0.6.0)
46
+ tty-markdown (0.7.0)
47
+ kramdown (>= 1.16.2, < 3.0)
48
+ pastel (~> 0.8)
49
+ rouge (~> 3.14)
50
+ strings (~> 0.2.0)
51
+ tty-color (~> 0.5)
52
+ tty-screen (~> 0.8)
53
+ tty-pager (0.14.0)
54
+ strings (~> 0.2.0)
55
+ tty-screen (~> 0.8)
56
+ tty-screen (0.8.1)
57
+ tzinfo (2.0.4)
58
+ concurrent-ruby (~> 1.0)
59
+ unicode-display_width (2.0.0)
61
60
  unicode_utils (1.4.0)
62
- zeitwerk (2.1.10)
61
+ zeitwerk (2.4.2)
63
62
 
64
63
  PLATFORMS
65
- ruby
64
+ x86_64-linux
66
65
 
67
66
  DEPENDENCIES
68
67
  jwtear!
69
68
 
70
69
  BUNDLED WITH
71
- 2.0.2
70
+ 2.2.25
data/bin/jwtear CHANGED
@@ -46,7 +46,7 @@ module JWTear
46
46
  exit!
47
47
  end
48
48
 
49
- puts banner if ARGV.empty?
49
+ puts banner if ARGV.empty?
50
50
  on_error do |exception|
51
51
  puts banner
52
52
  case exception
@@ -58,6 +58,8 @@ module JWTear
58
58
  print_error "Option #{exception.message}"
59
59
  when GLI::UnknownCommandArgument
60
60
  print_error "#{exception.message}"
61
+ when GLI::UnknownCommand
62
+ print_error "#{exception.message}"
61
63
  else
62
64
  print_error "Unknown Exception:"
63
65
  print_warning 'Please report the issue to: https://github.com/KINGSABRI/jwtear/issues'.underline
data/jwtear.gemspec CHANGED
@@ -18,11 +18,12 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = ['jwtear']
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'gli', '~> 2.19', '>= 2.19.0'
22
- spec.add_dependency 'json-jwt', '~> 1.10', '>= 1.10.2'
21
+ spec.add_dependency 'gli', '~> 2.20', '>= 2.20.0'
22
+ spec.add_dependency 'json-jwt', '~> 1.13.0'
23
23
  spec.add_dependency 'jwe', "~> 0.4.0"
24
- spec.add_dependency 'tty-markdown', "~> 0.6.0"
25
- spec.add_dependency 'tty-pager', "~> 0.12.1"
24
+ spec.add_dependency 'tty-markdown', "~> 0.7.0"
25
+ spec.add_dependency 'tty-pager', "~> 0.14.0"
26
+ spec.add_dependency 'colorize', "~> 0.8.1"
26
27
 
27
28
  # spec.add_development_dependency('rake', '~> 0.9.2.2')
28
29
  end
@@ -19,32 +19,34 @@ module JWTear
19
19
 
20
20
  # read key as a string or from file(eg. pub_key.pem)
21
21
  def read_key(key)
22
- if key
23
- File.file?(key)? File.read(key) : key
22
+ if File.file?(File.absolute_path(key))
23
+ File.read(File.absolute_path(key))
24
+ else
25
+ key
24
26
  end
25
27
  end
26
28
 
27
29
  # check_dependencies
28
30
  # check dependencies for plugins and throw a gentle error if not installed
29
31
  # @param deps [Hash]
30
- # The key is the library to be require, the key is the gem to be required
32
+ # The key is the key is the gem name to be installed, the value is library to be require
31
33
  # @example
32
34
  # deps = {'async-io' => 'async/ip'}
33
35
  # check_dependencies(deps)
34
36
  #
35
37
  def check_dependencies(deps={})
36
- return if deps.empty?
38
+ return if deps.empty? or deps.nil?
37
39
  missing = []
38
40
 
39
- deps.each do |gem, req|
41
+ deps.each do |gem, lib|
40
42
  begin
41
- require req
43
+ require lib
42
44
  rescue LoadError
43
45
  missing << gem
44
46
  end
45
47
  end
46
48
  ensure
47
- unless missing.empty?
49
+ unless missing.nil? or missing.empty?
48
50
  print_error "Missing dependencies!"
49
51
  print_warning "Please install as follows:"
50
52
  puts "gem install #{missing.join(' ')}"
data/lib/jwtear/jwe.rb CHANGED
@@ -58,10 +58,10 @@ module JWTear
58
58
  cipher_text = Base64.urlsafe_encode64(@cipher_text, padding: false)
59
59
  authentication_tag = Base64.urlsafe_encode64(@authentication_tag, padding: false)
60
60
 
61
- "#{header.to_json}" + "" +
62
- "#{encrypted_key}" + "" +
63
- "#{iv}" + "" +
64
- "#{cipher_text}" + "" +
61
+ "#{header.to_json}" + ".".bold +
62
+ "#{encrypted_key}" + ".".bold +
63
+ "#{iv}" + ".".bold +
64
+ "#{cipher_text}" + ".".bold +
65
65
  "#{authentication_tag}"
66
66
  end
67
67
 
@@ -78,7 +78,7 @@ module JWTear
78
78
  key = OpenSSL::PKey::RSA.new(key)
79
79
  jwt = JSON::JWT.new(JSON.parse(payload, symbolize_names: true))
80
80
  jwt.header = JSON.parse(header, symbolize_names: true)
81
- ::JWE.encrypt(payload, key, enc: jwt.header[:enc]) # I had to use this gem as json-jwt does not support A192GCM AFAIK
81
+ ::JWE.encrypt(payload, key, enc: jwt.header[:enc]) # I had to use this gem as jwe does not support A192GCM AFAIK
82
82
  rescue TypeError => e
83
83
  print_bad "Invalid data type."
84
84
  print_warning "Make sure your public/private key file exists."
data/lib/jwtear/jws.rb CHANGED
@@ -39,7 +39,7 @@ module JWTear
39
39
  end
40
40
 
41
41
  def to_json_presentation
42
- "#{@header.to_json}" + "" + "#{@payload.to_json}" + "" + "#{Base64.urlsafe_encode64(@signature, padding: false)}"
42
+ "#{@header.to_json}" + ".".bold + "#{@payload.to_json}" + ".".bold + "#{Base64.urlsafe_encode64(@signature, padding: false)}"
43
43
  end
44
44
 
45
45
  # generate_jws
@@ -59,6 +59,8 @@ module JWTear
59
59
  puts "Unexpected algorithm '#{jwt.header[:alg]}'."
60
60
  puts e.message
61
61
  exit!
62
+ rescue Exception => e
63
+ print_error e.message
62
64
  end
63
65
 
64
66
  private
@@ -73,6 +75,24 @@ module JWTear
73
75
  jwt.to_s
74
76
  else
75
77
  raise JSON::JWS::UnexpectedAlgorithm.new("Encryption algorithm '#{jwt.alg}' requires key.") if key.nil?
78
+ alg = jwt.alg.upcase
79
+ case
80
+ when alg.start_with?("HS")
81
+ key
82
+ when alg.start_with?("RS")
83
+ key = OpenSSL::PKey::RSA.new(key)
84
+ when alg.start_with?("PS")
85
+ key = OpenSSL::PKey::RSA.new(key)
86
+ when alg.start_with?("ES")
87
+ # key = OpenSSL::PKey::RSA.new(key)
88
+ print_error("Signing for ECDSA-SHA is not yet implemented")
89
+ print_warning 'Please report the issue to: https://github.com/KINGSABRI/jwtear/issues'.underline
90
+ else
91
+ print_warning("Undefined algorithm. This might generate a wrong token")
92
+ print_warning 'Please report the issue to: https://github.com/KINGSABRI/jwtear/issues'.underline
93
+ key
94
+ end
95
+ jwt.alg = alg.to_sym
76
96
  jwt.sign(key).to_s
77
97
  end
78
98
  end
data/lib/jwtear/token.rb CHANGED
@@ -23,10 +23,9 @@ module JWTear
23
23
  @jwe.parse(token)
24
24
  end
25
25
  rescue Exception => e
26
- print_error "Unknown Exception: #{method(__method__).owner}"
26
+ print_error "#{method(__method__).owner}##{__method__} : Unknown Exception"
27
27
  print_warning 'Please report the issue to: https://github.com/KINGSABRI/jwtear/issues'.underline
28
- puts e
29
- puts e.backtrace
28
+ puts e.full_message
30
29
  exit!
31
30
  end
32
31
 
@@ -1,3 +1,3 @@
1
1
  module JWTear
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.7"
3
3
  end
@@ -33,7 +33,7 @@ module JWTear
33
33
  include JWTear::Helpers::Utils
34
34
 
35
35
  def initialize(token, list)
36
- deps = {'async-io' => 'async/io'}
36
+ deps = {}
37
37
  check_dependencies(deps)
38
38
  @token = Token.new
39
39
  @jws = @token.parse(token)
@@ -48,7 +48,7 @@ module JWTear
48
48
  key.valid_encoding? ? key.strip! : next
49
49
  print_status "Trying password: #{key}" if verbose
50
50
 
51
- gen_token = @token.generate(:jws, header: @jws.header.to_json, payload:@jws.payload.to_json , key: key)
51
+ gen_token = @token.generate(:jws, header: @jws.header.to_json, payload: @jws.payload.to_json , key: key)
52
52
  sig = gen_token.split('.').last
53
53
  if sig == Base64.urlsafe_encode64(@jws.signature, padding: false)
54
54
  print_good "Password found: #{key}"
@@ -59,7 +59,7 @@ module JWTear
59
59
  end
60
60
  end
61
61
  when keys.kind_of?(String)
62
- gen_token = @token.generate(:jws, header: @jws.header.to_json, payload:@jws.payload.to_json , key: keys)
62
+ gen_token = @token.generate(:jws, header: @jws.header.to_json, payload: @jws.payload.to_json , key: keys)
63
63
  sig = gen_token.split('.').last
64
64
  if sig == Base64.urlsafe_encode64(@jws.signature, padding: false)
65
65
  print_good "Password found: #{keys}"
data/plugins/generate.rb CHANGED
@@ -20,7 +20,7 @@ module JWTear
20
20
  jws_cmd.desc "Key as a password string or a file public key. eg. P@ssw0rd | eg. public_key.pem"
21
21
  jws_cmd.arg_name 'PASSWORD|PUB_KEY_FILE'
22
22
  jws_cmd.flag [:k, :key]
23
- jws_cmd.action do |global, options, args|
23
+ jws_cmd.action do |_, options, _|
24
24
  gen = Generate.new
25
25
  puts gen.jws_token(options[:header], options[:payload], read_key(options[:key]))
26
26
  end
@@ -198,6 +198,7 @@ _source(JWT, JWS and JWE for Not So Dummies! (Part I))_
198
198
  * [Pentesterlab(PRO) - JWT X](https://pentesterlab.com/exercises/jwt_x/)
199
199
  * [Pentesterlab(PRO) - JWT XI](https://pentesterlab.com/exercises/jwt_xi)
200
200
  * [Pentesterlab(PRO) - JWT XII](https://pentesterlab.com/exercises/jwt_xii)
201
+ * [Pentesterlab(PRO) - JWT XIII](https://pentesterlab.com/exercises/jwt_iii)
201
202
  * [Pentesterlab(PRO) - JSON Web Encryption](https://pentesterlab.com/exercises/jwe)
202
203
  * [Vulnerable JWT implementations](https://github.com/Sjord/jwtdemo)
203
204
 
@@ -212,3 +213,4 @@ _source(JWT, JWS and JWE for Not So Dummies! (Part I))_
212
213
  * [Damn Vulnerable Service](https://github.com/snoopysecurity/dvws)
213
214
  * [CSRF JWT redirect leak](https://gist.github.com/stefanocoding/8cdc8acf5253725992432dedb1c9c781)
214
215
  * [Critical vulnerabilities in JSON Web Token libraries](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/)
216
+ * [JWT Attack Playbook](https://github.com/ticarpi/jwt_tool/wiki)
data/plugins/wiki.rb CHANGED
@@ -5,7 +5,7 @@ module JWTear
5
5
  extend JWTear::Helpers::Utils
6
6
 
7
7
  desc "A JWT wiki for hackers."
8
- long_desc "Wiki wiki Wiki wiki Wiki wiki Wiki wiki Wiki wiki Wiki wiki"
8
+ long_desc "A JWT wiki contains introduction, attack ideas, vulnerable application links and resources."
9
9
  command [:wiki, :w] do |c|
10
10
 
11
11
  c.desc "Show the wiki page on terminal"
@@ -34,7 +34,7 @@ module JWTear
34
34
  require 'open-uri'
35
35
  print_status 'Updating wiki'
36
36
  current_wiki = File.expand_path(File.join(__dir__ , 'wiki', 'README.md'))
37
- updated_wiki = open('https://raw.githubusercontent.com/KINGSABRI/jwtear/master/plugins/wiki/README.md').read
37
+ updated_wiki = URI.open('https://raw.githubusercontent.com/KINGSABRI/jwtear/master/plugins/wiki/README.md').read
38
38
  if File.exists?(current_wiki) && File.writable?(current_wiki)
39
39
  File.write(current_wiki, updated_wiki)
40
40
  else
metadata CHANGED
@@ -1,55 +1,49 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwtear
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - KING SABRI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-07 00:00:00.000000000 Z
11
+ date: 2021-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gli
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.19'
20
17
  - - ">="
21
18
  - !ruby/object:Gem::Version
22
- version: 2.19.0
19
+ version: 2.20.0
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '2.20'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '2.19'
30
27
  - - ">="
31
28
  - !ruby/object:Gem::Version
32
- version: 2.19.0
29
+ version: 2.20.0
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.20'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: json-jwt
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.10'
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 1.10.2
39
+ version: 1.13.0
43
40
  type: :runtime
44
41
  prerelease: false
45
42
  version_requirements: !ruby/object:Gem::Requirement
46
43
  requirements:
47
44
  - - "~>"
48
45
  - !ruby/object:Gem::Version
49
- version: '1.10'
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 1.10.2
46
+ version: 1.13.0
53
47
  - !ruby/object:Gem::Dependency
54
48
  name: jwe
55
49
  requirement: !ruby/object:Gem::Requirement
@@ -70,28 +64,42 @@ dependencies:
70
64
  requirements:
71
65
  - - "~>"
72
66
  - !ruby/object:Gem::Version
73
- version: 0.6.0
67
+ version: 0.7.0
74
68
  type: :runtime
75
69
  prerelease: false
76
70
  version_requirements: !ruby/object:Gem::Requirement
77
71
  requirements:
78
72
  - - "~>"
79
73
  - !ruby/object:Gem::Version
80
- version: 0.6.0
74
+ version: 0.7.0
81
75
  - !ruby/object:Gem::Dependency
82
76
  name: tty-pager
83
77
  requirement: !ruby/object:Gem::Requirement
84
78
  requirements:
85
79
  - - "~>"
86
80
  - !ruby/object:Gem::Version
87
- version: 0.12.1
81
+ version: 0.14.0
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.14.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: colorize
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 0.8.1
88
96
  type: :runtime
89
97
  prerelease: false
90
98
  version_requirements: !ruby/object:Gem::Requirement
91
99
  requirements:
92
100
  - - "~>"
93
101
  - !ruby/object:Gem::Version
94
- version: 0.12.1
102
+ version: 0.8.1
95
103
  description: JWTear, a modular command-line tool to parse, create and manipulate JWT
96
104
  tokens for security testing purposes.
97
105
  email:
@@ -101,6 +109,7 @@ executables:
101
109
  extensions: []
102
110
  extra_rdoc_files: []
103
111
  files:
112
+ - ".github/workflows/gem-push.yml"
104
113
  - ".gitignore"
105
114
  - CODE_OF_CONDUCT.md
106
115
  - Gemfile
@@ -142,8 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
151
  - !ruby/object:Gem::Version
143
152
  version: '0'
144
153
  requirements: []
145
- rubyforge_project:
146
- rubygems_version: 2.7.6.2
154
+ rubygems_version: 3.0.3.1
147
155
  signing_key:
148
156
  specification_version: 4
149
157
  summary: JWTear, a modular command-line tool to parse, create and manipulate JWT tokens