usps-jwt_auth 1.0.6 → 1.1.0

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: 2b570538c78235e550ff7903dfb293cbf8d7116ee050af858a963db6ddc84c2e
4
- data.tar.gz: e41a91e29de1b8449780e39d0bf93b8ca61f3f08eb43ff08f470ac244a2675ea
3
+ metadata.gz: be13d7639636f1abce28a82c032ea04883808bec8bb3925060f3f2071e1bf3ef
4
+ data.tar.gz: 8486bf2584dbcc901f00e17ef059ec3125db036f76f7c81080d68125177f50b0
5
5
  SHA512:
6
- metadata.gz: 8eaf955b197330910784b35669dec3ef5d6cd073f910f66623188f2e6fa672c588e84ec45bea8f2e045b1809ff39241f356e398b501217d9a743a7f69b0b192f
7
- data.tar.gz: 73f575a6f21f5efa3fdbdf485f208d163d7d25b2de288ce641048acaf27b9f4809a36478278c785bb148843f470d503fbf5fb8e9395b71e089b149e0686248f2
6
+ metadata.gz: 2a8d5e69bd26ed1a65da6f4c7beb907aa570e7ae1942c4f256fee3c42e8f39bdcbc938018b626825ac77e5d50a64d6b994534361acfac8fda025c2681f39d4a3
7
+ data.tar.gz: 5fc08818ac1c3cd4b13b1005f294d6bfd0d3837fc03fd0609c74235cf9de706d5311fc01aaa44cb3cda34edcad22636f56807f6a0ac7d5e7e7b5c79a43048f5f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- usps-jwt_auth (1.0.6)
4
+ usps-jwt_auth (1.1.0)
5
5
  activesupport (~> 8.0)
6
6
  colorize (~> 1.1)
7
7
  fileutils (~> 1.7)
@@ -49,7 +49,9 @@ GEM
49
49
  language_server-protocol (3.17.0.5)
50
50
  lint_roller (1.1.0)
51
51
  logger (1.7.0)
52
- minitest (5.26.0)
52
+ minitest (6.0.6)
53
+ drb (~> 2.0)
54
+ prism (~> 1.5)
53
55
  parallel (1.27.0)
54
56
  parser (3.3.9.0)
55
57
  ast (~> 2.4.1)
@@ -118,7 +120,7 @@ GEM
118
120
  concurrent-ruby (~> 1.0)
119
121
  unicode-display_width (3.2.0)
120
122
  unicode-emoji (~> 4.1)
121
- unicode-emoji (4.1.0)
123
+ unicode-emoji (4.2.0)
122
124
  uri (1.0.4)
123
125
 
124
126
  PLATFORMS
@@ -54,7 +54,7 @@ module Usps
54
54
 
55
55
  # Admin has entered impersonation mode -- override current_user
56
56
  @current_user = JwtAuth.config.find_member.call(session['impersonate']['impersonated'])
57
- rescue JWT::ExpiredSignature
57
+ rescue JWT::DecodeError
58
58
  clear_jwt
59
59
  nil
60
60
  rescue ActiveRecord::RecordNotFound => e
@@ -34,6 +34,10 @@ module Usps
34
34
 
35
35
  def public_key(token)
36
36
  OpenSSL::PKey::RSA.new(File.read("#{JwtAuth.config.public_keys_path}/#{fingerprint(token)}.pub"))
37
+ rescue Errno::ENOENT
38
+ # No public key matches the token's fingerprint (e.g. a stale token after key rotation),
39
+ # so the token cannot be verified and is treated as invalid.
40
+ raise JWT::VerificationError, 'No public key for token fingerprint'
37
41
  end
38
42
 
39
43
  def fingerprint(token)
@@ -30,12 +30,34 @@ module Usps
30
30
  @public_key ||= private_key.public_key
31
31
  end
32
32
 
33
+ # OpenSSH-style SHA256 key fingerprint: base64url(SHA256(ssh-rsa wire blob)),
34
+ # i.e. the value `ssh-keygen -lf` prints as `SHA256:...`. This matches the key
35
+ # filenames and `key` claim that the consuming apps already recognize.
33
36
  def fingerprint
34
- OpenSSL::Digest::SHA256.new(public_key.to_der).to_s
37
+ digest = OpenSSL::Digest::SHA256.digest(ssh_public_blob)
38
+ [digest].pack('m0').tr('+/', '-_').delete('=')
35
39
  end
36
40
 
37
41
  private
38
42
 
43
+ # Public key in the OpenSSH wire format: string('ssh-rsa') + mpint(e) + mpint(n).
44
+ def ssh_public_blob
45
+ ssh_string('ssh-rsa') + ssh_mpint(public_key.e) + ssh_mpint(public_key.n)
46
+ end
47
+
48
+ # SSH "string": 4-byte big-endian length prefix followed by the bytes.
49
+ def ssh_string(bytes)
50
+ [bytes.bytesize].pack('N') + bytes.b
51
+ end
52
+
53
+ # SSH "mpint": a length-prefixed big-endian integer; a leading zero byte is
54
+ # prepended when the high bit is set so the value stays non-negative.
55
+ def ssh_mpint(num)
56
+ bytes = num.to_s(2)
57
+ bytes = "\x00".b + bytes if bytes.bytes.first && bytes.bytes.first >= 0x80
58
+ ssh_string(bytes)
59
+ end
60
+
39
61
  def expires_at
40
62
  ::Time.now.to_i + @expiration_time
41
63
  end
@@ -64,8 +86,12 @@ module Usps
64
86
  ::FileUtils.chmod(0o600, path)
65
87
  end
66
88
 
89
+ # Ensure the public key is published, but only write it when missing — the file
90
+ # is stable for a given key, so rewriting it on every encode is needless churn.
67
91
  def store_public_key
68
92
  path = "#{JwtAuth.config.public_keys_path}/#{fingerprint}.pub"
93
+ return if File.exist?(path)
94
+
69
95
  File.open(path, 'w+') { |f| f.puts(public_key) }
70
96
  ::FileUtils.chmod(0o644, path)
71
97
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module JwtAuth
5
- VERSION = '1.0.6'
5
+ VERSION = '1.1.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: usps-jwt_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Fiander