ruby-paseto 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +8 -0
  3. data/CODE_OF_CONDUCT.md +84 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +549 -0
  6. data/lib/paseto/asn1/algorithm_identifier.rb +17 -0
  7. data/lib/paseto/asn1/curve_private_key.rb +22 -0
  8. data/lib/paseto/asn1/ec_private_key.rb +27 -0
  9. data/lib/paseto/asn1/ecdsa_full_r.rb +26 -0
  10. data/lib/paseto/asn1/ecdsa_sig_value.rb +23 -0
  11. data/lib/paseto/asn1/ecdsa_signature.rb +49 -0
  12. data/lib/paseto/asn1/ed25519_identifier.rb +15 -0
  13. data/lib/paseto/asn1/named_curve.rb +17 -0
  14. data/lib/paseto/asn1/one_asymmetric_key.rb +32 -0
  15. data/lib/paseto/asn1/private_key.rb +17 -0
  16. data/lib/paseto/asn1/private_key_algorithm_identifier.rb +17 -0
  17. data/lib/paseto/asn1/public_key.rb +17 -0
  18. data/lib/paseto/asn1/subject_public_key_info.rb +28 -0
  19. data/lib/paseto/asn1.rb +101 -0
  20. data/lib/paseto/asymmetric_key.rb +100 -0
  21. data/lib/paseto/configuration/box.rb +23 -0
  22. data/lib/paseto/configuration/decode_configuration.rb +68 -0
  23. data/lib/paseto/configuration.rb +18 -0
  24. data/lib/paseto/interface/i_d.rb +23 -0
  25. data/lib/paseto/interface/key.rb +113 -0
  26. data/lib/paseto/interface/pbkd.rb +83 -0
  27. data/lib/paseto/interface/pie.rb +59 -0
  28. data/lib/paseto/interface/pke.rb +86 -0
  29. data/lib/paseto/interface/serializer.rb +19 -0
  30. data/lib/paseto/interface/version.rb +161 -0
  31. data/lib/paseto/interface/wrapper.rb +20 -0
  32. data/lib/paseto/operations/i_d.rb +48 -0
  33. data/lib/paseto/operations/id/i_dv3.rb +20 -0
  34. data/lib/paseto/operations/id/i_dv4.rb +20 -0
  35. data/lib/paseto/operations/pbkd/p_b_k_dv3.rb +85 -0
  36. data/lib/paseto/operations/pbkd/p_b_k_dv4.rb +94 -0
  37. data/lib/paseto/operations/pbkw.rb +73 -0
  38. data/lib/paseto/operations/pke/p_k_ev3.rb +97 -0
  39. data/lib/paseto/operations/pke/p_k_ev4.rb +95 -0
  40. data/lib/paseto/operations/pke.rb +57 -0
  41. data/lib/paseto/operations/wrap.rb +29 -0
  42. data/lib/paseto/paserk.rb +55 -0
  43. data/lib/paseto/paserk_types.rb +46 -0
  44. data/lib/paseto/protocol/version3.rb +100 -0
  45. data/lib/paseto/protocol/version4.rb +99 -0
  46. data/lib/paseto/result.rb +9 -0
  47. data/lib/paseto/serializer/optional_json.rb +30 -0
  48. data/lib/paseto/serializer/raw.rb +23 -0
  49. data/lib/paseto/sodium/curve_25519.rb +46 -0
  50. data/lib/paseto/sodium/safe_ed25519_loader.rb +19 -0
  51. data/lib/paseto/sodium/stream/base.rb +82 -0
  52. data/lib/paseto/sodium/stream/x_cha_cha20_xor.rb +31 -0
  53. data/lib/paseto/sodium.rb +5 -0
  54. data/lib/paseto/symmetric_key.rb +119 -0
  55. data/lib/paseto/token.rb +127 -0
  56. data/lib/paseto/token_types.rb +29 -0
  57. data/lib/paseto/util.rb +105 -0
  58. data/lib/paseto/v3/local.rb +63 -0
  59. data/lib/paseto/v3/public.rb +204 -0
  60. data/lib/paseto/v4/local.rb +56 -0
  61. data/lib/paseto/v4/public.rb +169 -0
  62. data/lib/paseto/validator.rb +154 -0
  63. data/lib/paseto/verifiers/footer.rb +30 -0
  64. data/lib/paseto/verifiers/payload.rb +42 -0
  65. data/lib/paseto/verify.rb +48 -0
  66. data/lib/paseto/version.rb +6 -0
  67. data/lib/paseto/versions.rb +25 -0
  68. data/lib/paseto/wrappers/pie/pie_v3.rb +72 -0
  69. data/lib/paseto/wrappers/pie/pie_v4.rb +72 -0
  70. data/lib/paseto/wrappers/pie.rb +71 -0
  71. data/lib/paseto.rb +99 -0
  72. data/paseto.gemspec +58 -0
  73. data/sorbet/config +3 -0
  74. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  75. data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
  76. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1083 -0
  77. data/sorbet/rbi/gems/docile@1.4.0.rbi +376 -0
  78. data/sorbet/rbi/gems/ffi@1.15.5.rbi +1994 -0
  79. data/sorbet/rbi/gems/io-console@0.5.11.rbi +8 -0
  80. data/sorbet/rbi/gems/irb@1.5.1.rbi +342 -0
  81. data/sorbet/rbi/gems/json@2.6.3.rbi +1541 -0
  82. data/sorbet/rbi/gems/multi_json@1.15.0.rbi +267 -0
  83. data/sorbet/rbi/gems/netrc@0.11.0.rbi +158 -0
  84. data/sorbet/rbi/gems/oj@3.13.23.rbi +603 -0
  85. data/sorbet/rbi/gems/openssl@3.0.1.rbi +1735 -0
  86. data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
  87. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +407 -0
  88. data/sorbet/rbi/gems/rake@13.0.6.rbi +3021 -0
  89. data/sorbet/rbi/gems/rbnacl@7.1.1.rbi +3218 -0
  90. data/sorbet/rbi/gems/regexp_parser@2.6.1.rbi +3481 -0
  91. data/sorbet/rbi/gems/reline@0.3.1.rbi +8 -0
  92. data/sorbet/rbi/gems/rexml@3.2.5.rbi +4717 -0
  93. data/sorbet/rbi/gems/rspec-core@3.12.0.rbi +10887 -0
  94. data/sorbet/rbi/gems/rspec-expectations@3.12.0.rbi +8090 -0
  95. data/sorbet/rbi/gems/rspec-mocks@3.12.0.rbi +5300 -0
  96. data/sorbet/rbi/gems/rspec-support@3.12.0.rbi +1617 -0
  97. data/sorbet/rbi/gems/rspec@3.12.0.rbi +88 -0
  98. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +1239 -0
  99. data/sorbet/rbi/gems/simplecov-html@0.12.3.rbi +219 -0
  100. data/sorbet/rbi/gems/simplecov@0.21.2.rbi +2135 -0
  101. data/sorbet/rbi/gems/simplecov_json_formatter@0.1.4.rbi +8 -0
  102. data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
  103. data/sorbet/rbi/gems/timecop@0.9.6.rbi +350 -0
  104. data/sorbet/rbi/gems/unicode-display_width@2.3.0.rbi +48 -0
  105. data/sorbet/rbi/gems/webrick@1.7.0.rbi +2555 -0
  106. data/sorbet/rbi/gems/yard-sorbet@0.7.0.rbi +391 -0
  107. data/sorbet/rbi/gems/yard@0.9.28.rbi +17816 -0
  108. data/sorbet/rbi/gems/zeitwerk@2.6.6.rbi +950 -0
  109. data/sorbet/rbi/shims/multi_json.rbi +19 -0
  110. data/sorbet/rbi/shims/openssl.rbi +111 -0
  111. data/sorbet/rbi/shims/rbnacl.rbi +65 -0
  112. data/sorbet/rbi/shims/zeitwerk.rbi +6 -0
  113. data/sorbet/rbi/todo.rbi +7 -0
  114. data/sorbet/tapioca/config.yml +30 -0
  115. data/sorbet/tapioca/require.rb +12 -0
  116. metadata +376 -0
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class AlgorithmIdentifier < T::Struct
7
+ extend T::Sig
8
+
9
+ const :algorithm, NamedCurve
10
+
11
+ sig { returns(OpenSSL::ASN1::Sequence) }
12
+ def build
13
+ OpenSSL::ASN1::Sequence.new(algorithm.build)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class CurvePrivateKey < T::Struct
7
+ extend T::Sig
8
+
9
+ const :private_key, String
10
+
11
+ sig { returns(OpenSSL::ASN1::OctetString) }
12
+ def build
13
+ OpenSSL::ASN1::OctetString.new(private_key)
14
+ end
15
+
16
+ sig { returns(String) }
17
+ def to_der
18
+ build.to_der
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class ECPrivateKey < T::Struct
7
+ extend T::Sig
8
+
9
+ const :private_key, String
10
+
11
+ sig { returns(OpenSSL::ASN1::Sequence) }
12
+ def build
13
+ OpenSSL::ASN1::Sequence.new(
14
+ [
15
+ OpenSSL::ASN1::Integer.new(1),
16
+ OpenSSL::ASN1::OctetString.new(private_key)
17
+ ]
18
+ )
19
+ end
20
+
21
+ sig { returns(String) }
22
+ def to_der
23
+ build.to_der
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class ECDSAFullR < T::Struct
7
+ extend T::Sig
8
+
9
+ const :r, OpenSSL::PKey::EC::Point
10
+ const :s, OpenSSL::BN
11
+
12
+ sig { returns(OpenSSL::ASN1::Sequence) }
13
+ def build
14
+ # Unsupported by OpenSSL 3.0
15
+ # :nocov:
16
+ OpenSSL::ASN1::Sequence.new(
17
+ [
18
+ OpenSSL::ASN1::OctetString.new(r.to_octet_string(:compressed)),
19
+ OpenSSL::ASN1::Integer.new(s)
20
+ ]
21
+ )
22
+ # :nocov:
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class ECDSASigValue < T::Struct
7
+ extend T::Sig
8
+
9
+ const :r, OpenSSL::BN
10
+ const :s, OpenSSL::BN
11
+
12
+ sig { returns(OpenSSL::ASN1::Sequence) }
13
+ def build
14
+ OpenSSL::ASN1::Sequence.new(
15
+ [
16
+ OpenSSL::ASN1::Integer.new(r),
17
+ OpenSSL::ASN1::Integer.new(s)
18
+ ]
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class ECDSASignature < T::Struct
7
+ extend T::Sig
8
+
9
+ const :signature, T.any(ECDSASigValue, ECDSAFullR)
10
+
11
+ sig { params(bytes: String, part_len: Integer).returns(ECDSASignature) }
12
+ def self.from_rs(bytes, part_len)
13
+ r = OpenSSL::BN.new(T.must(bytes[0, part_len]), 2)
14
+ s = OpenSSL::BN.new(T.must(bytes[-part_len, part_len]), 2)
15
+ new(signature: ECDSASigValue.new(r: r, s: s))
16
+ end
17
+
18
+ sig { params(sig: String).returns(ECDSASignature) }
19
+ def self.from_asn1(sig)
20
+ r, s = OpenSSL::ASN1.decode(sig).value.map(&:value)
21
+ new(signature: ECDSASigValue.new(r: r, s: s))
22
+ end
23
+
24
+ sig { returns(OpenSSL::ASN1::Sequence) }
25
+ def build
26
+ signature.build
27
+ end
28
+
29
+ sig { returns(String) }
30
+ def to_der
31
+ build.to_der
32
+ end
33
+
34
+ sig { params(part_len: Integer).returns(String) }
35
+ def to_rs(part_len)
36
+ case signature
37
+ when ECDSASigValue
38
+ r = T.cast(signature.r, OpenSSL::BN).to_s(2).rjust(part_len, "\x00")
39
+ when ECDSAFullR
40
+ # :nocov:
41
+ r = T.cast(signature.r, OpenSSL::PKey::EC::Point).to_octet_string(:compressed).rjust(part_len, "\x00")
42
+ # :nocov:
43
+ end
44
+ s = signature.s.to_s(2).rjust(part_len, "\x00")
45
+ [r, s].join
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class Ed25519Identifier < T::Struct
7
+ extend T::Sig
8
+
9
+ sig { returns([OpenSSL::ASN1::ObjectId]) }
10
+ def build
11
+ [OpenSSL::ASN1::ObjectId('ED25519')]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class NamedCurve < T::Struct
7
+ extend T::Sig
8
+
9
+ const :curve_name, String
10
+
11
+ sig { returns([OpenSSL::ASN1::ObjectId, OpenSSL::ASN1::ObjectId]) }
12
+ def build
13
+ [OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(curve_name)]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class OneAsymmetricKey < T::Struct
7
+ extend T::Sig
8
+
9
+ const :version, OpenSSL::BN
10
+ const :algorithm, PrivateKeyAlgorithmIdentifier
11
+ const :private_key, PrivateKey
12
+ const :public_key, T.nilable(PublicKey)
13
+
14
+ sig { returns(OpenSSL::ASN1::Sequence) }
15
+ def build
16
+ OpenSSL::ASN1::Sequence.new(
17
+ [
18
+ OpenSSL::ASN1::Integer.new(version),
19
+ algorithm.build,
20
+ private_key.build
21
+ # public_key&.build
22
+ ].compact
23
+ )
24
+ end
25
+
26
+ sig { returns(String) }
27
+ def to_der
28
+ build.to_der
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class PrivateKey < T::Struct
7
+ extend T::Sig
8
+
9
+ const :private_key, T.any(ECPrivateKey, CurvePrivateKey)
10
+
11
+ sig { returns(OpenSSL::ASN1::OctetString) }
12
+ def build
13
+ OpenSSL::ASN1::OctetString.new(private_key.to_der)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class PrivateKeyAlgorithmIdentifier < T::Struct
7
+ extend T::Sig
8
+
9
+ const :parameters, T.any(Ed25519Identifier, NamedCurve)
10
+
11
+ sig { returns(OpenSSL::ASN1::Sequence) }
12
+ def build
13
+ OpenSSL::ASN1::Sequence.new(parameters.build)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class PublicKey < T::Struct
7
+ extend T::Sig
8
+
9
+ const :public_key, String
10
+
11
+ sig { returns(OpenSSL::ASN1::BitString) }
12
+ def build
13
+ OpenSSL::ASN1::BitString.new(public_key)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ class SubjectPublicKeyInfo < T::Struct
7
+ extend T::Sig
8
+
9
+ const :algorithm_identifier, AlgorithmIdentifier
10
+ const :public_key, PublicKey
11
+
12
+ sig { returns(OpenSSL::ASN1::Sequence) }
13
+ def build
14
+ OpenSSL::ASN1::Sequence.new(
15
+ [
16
+ algorithm_identifier.build,
17
+ public_key.build
18
+ ]
19
+ )
20
+ end
21
+
22
+ sig { returns(String) }
23
+ def to_der
24
+ build.to_der
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,101 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module ASN1
6
+ # References:
7
+ # https://www.rfc-editor.org/rfc/rfc5208 PKCS #8: Private-Key Information Syntax Specification Version 1.2
8
+ # https://www.rfc-editor.org/rfc/rfc5480 Elliptic Curve Cryptography Subject Public Key Information
9
+ # https://www.rfc-editor.org/rfc/rfc5915 Elliptic Curve Private Key Structure
10
+ # https://www.rfc-editor.org/rfc/rfc5958 Asymmetric Key Packages (obsoletes PKCS#8)
11
+ # https://www.rfc-editor.org/rfc/rfc8018 PKCS #5: Password-Based Cryptography Specification Version 2.1
12
+ # https://www.secg.org/sec1-v2.pdf
13
+
14
+ extend T::Sig
15
+
16
+ sig { params(bytes: String).returns(String) }
17
+ def self.p384_scalar_bytes_to_oak_der(bytes)
18
+ OneAsymmetricKey.new(
19
+ version: OpenSSL::BN.new(1),
20
+ algorithm: PrivateKeyAlgorithmIdentifier.new(
21
+ parameters: NamedCurve.new(curve_name: 'secp384r1')
22
+ ),
23
+ private_key: PrivateKey.new(
24
+ private_key: ECPrivateKey.new(
25
+ private_key: bytes
26
+ )
27
+ )
28
+ ).to_der
29
+ end
30
+
31
+ sig { params(bytes: String).returns(String) }
32
+ def self.p384_public_bytes_to_spki_der(bytes)
33
+ SubjectPublicKeyInfo.new(
34
+ algorithm_identifier: AlgorithmIdentifier.new(
35
+ algorithm: NamedCurve.new(curve_name: 'secp384r1')
36
+ ),
37
+ public_key: PublicKey.new(
38
+ public_key: bytes
39
+ )
40
+ ).to_der
41
+ end
42
+
43
+ # RbNaCl::SigningKey.keypair_bytes returns the 32-byte private scalar and group element
44
+ # as (s || g), so we repack that into an ASN1 structure and then Base64 the resulting DER
45
+ # to get a PEM.
46
+ sig { params(bytes: String).returns(String) }
47
+ def self.ed25519_rs_to_oak_der(bytes)
48
+ OneAsymmetricKey.new(
49
+ version: OpenSSL::BN.new(0),
50
+ algorithm: PrivateKeyAlgorithmIdentifier.new(
51
+ parameters: Ed25519Identifier.new
52
+ ),
53
+ private_key: PrivateKey.new(
54
+ private_key: CurvePrivateKey.new(
55
+ private_key: T.must(bytes.byteslice(0, 32))
56
+ )
57
+ )
58
+ ).to_der
59
+ end
60
+
61
+ sig { params(bytes: String).returns(String) }
62
+ def self.ed25519_rs_to_oak_pem(bytes)
63
+ der_to_private_pem(ed25519_rs_to_oak_der(bytes))
64
+ end
65
+
66
+ sig { params(verify_key: String).returns(String) }
67
+ def self.ed25519_pubkey_nacl_to_der(verify_key)
68
+ OpenSSL::ASN1::Sequence.new(
69
+ [
70
+ OpenSSL::ASN1::Sequence.new(
71
+ [OpenSSL::ASN1::ObjectId.new('ED25519')]
72
+ ),
73
+ OpenSSL::ASN1::BitString.new(verify_key)
74
+ ]
75
+ ).to_der
76
+ end
77
+
78
+ sig { params(verify_key: String).returns(String) }
79
+ def self.ed25519_pubkey_nacl_to_pem(verify_key)
80
+ der_to_public_pem(ed25519_pubkey_nacl_to_der(verify_key))
81
+ end
82
+
83
+ sig { params(der: String).returns(String) }
84
+ def self.der_to_public_pem(der)
85
+ <<~PEM
86
+ -----BEGIN PUBLIC KEY-----
87
+ #{Base64.strict_encode64(der)}
88
+ -----END PUBLIC KEY-----
89
+ PEM
90
+ end
91
+
92
+ sig { params(der: String).returns(String) }
93
+ def self.der_to_private_pem(der)
94
+ <<~PEM
95
+ -----BEGIN PRIVATE KEY-----
96
+ #{Base64.strict_encode64(der)}
97
+ -----END PRIVATE KEY-----
98
+ PEM
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,100 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ class AsymmetricKey < Interface::Key
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ abstract!
10
+
11
+ sig(:final) { override.returns(String) }
12
+ attr_reader :id, :paserk
13
+
14
+ sig(:final) { returns(String) }
15
+ attr_reader :pid, :public_paserk
16
+
17
+ sig { params(_key: T.untyped).void }
18
+ def initialize(_key)
19
+ @public_paserk = T.let("#{paserk_version}.public.#{Util.encode64(public_bytes)}".freeze, String)
20
+
21
+ @pid = T.let(Operations::ID.pid(self).freeze, String)
22
+
23
+ if private?
24
+ @paserk = T.let("#{paserk_version}.secret.#{Util.encode64(to_bytes)}".freeze, String)
25
+ @id = T.let(Operations::ID.sid(self).freeze, String)
26
+ else
27
+ @paserk = @public_paserk
28
+ @id = T.let(@pid, String)
29
+ end
30
+ end
31
+
32
+ sig { abstract.params(message: String, footer: String, implicit_assertion: String).returns(Token) }
33
+ def sign(message:, footer: '', implicit_assertion: ''); end
34
+
35
+ sig { abstract.params(token: Token, implicit_assertion: String).returns(String) }
36
+ def verify(token:, implicit_assertion: ''); end
37
+
38
+ sig { abstract.returns(String) }
39
+ def public_to_pem; end
40
+
41
+ sig { abstract.returns(String) }
42
+ def private_to_pem; end
43
+
44
+ sig { abstract.returns(T::Boolean) }
45
+ def private?; end
46
+
47
+ sig { abstract.returns(String) }
48
+ def public_bytes; end
49
+
50
+ sig { abstract.params(other: T.untyped).returns(String) }
51
+ def ecdh(other); end
52
+
53
+ sig(:final) do
54
+ override.params(
55
+ payload: T::Hash[String, T.untyped],
56
+ footer: String,
57
+ implicit_assertion: String,
58
+ options: T.nilable(T.any(String, Integer, Symbol, T::Boolean))
59
+ ).returns(String)
60
+ end
61
+ def encode!(payload, footer: '', implicit_assertion: '', **options)
62
+ MultiJson.dump(payload, options)
63
+ .then { |json| sign(message: json, footer: footer, implicit_assertion: implicit_assertion) }
64
+ .then(&:to_s)
65
+ end
66
+
67
+ sig(:final) do
68
+ override.params(
69
+ payload: String,
70
+ implicit_assertion: String,
71
+ options: T.nilable(T.any(Proc, String, Integer, Symbol, T::Boolean))
72
+ ).returns(Result)
73
+ end
74
+ def decode!(payload, implicit_assertion: '', **options)
75
+ token = Token.parse(payload)
76
+
77
+ verify(token: token, implicit_assertion: implicit_assertion)
78
+ .then { |json| MultiJson.load(json, **options) }
79
+ .then { |claims| Result.new(claims: claims, footer: token.footer) }
80
+ end
81
+
82
+ sig(:final) { override.returns(String) }
83
+ def pbkw_header = protocol.pbkd_secret_header
84
+
85
+ sig(:final) { override.returns(String) }
86
+ def purpose = 'public'
87
+
88
+ sig(:final) { returns(Interface::PKE) }
89
+ def pke = protocol.pke(self)
90
+
91
+ sig(:final) { returns(String) }
92
+ def sid = @sid ||= T.let(Operations::ID.sid(self), T.nilable(String))
93
+
94
+ sig(:final) { params(other: SymmetricKey).returns(String) }
95
+ def seal(other) = Paserk.seal(sealing_key: self, key: other)
96
+
97
+ sig(:final) { params(paserk: String).returns(SymmetricKey) }
98
+ def unseal(paserk) = Paserk.from_paserk(paserk: paserk, unsealing_key: self)
99
+ end
100
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module Configuration
6
+ class Box
7
+ extend T::Sig
8
+
9
+ sig { returns(DecodeConfiguration) }
10
+ attr_accessor :decode
11
+
12
+ sig { void }
13
+ def initialize
14
+ @decode = T.let(DecodeConfiguration.new, DecodeConfiguration)
15
+ end
16
+
17
+ sig { void }
18
+ def reset!
19
+ @decode = DecodeConfiguration.new
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,68 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module Configuration
6
+ class DecodeConfiguration
7
+ extend T::Sig
8
+
9
+ sig { returns(Interface::Serializer) }
10
+ attr_accessor :footer_serializer
11
+
12
+ sig { returns(T::Boolean) }
13
+ attr_accessor :verify_exp, :verify_nbf, :verify_iat
14
+
15
+ sig { returns(T.any(FalseClass, String)) }
16
+ attr_accessor :verify_sub
17
+
18
+ sig { returns(T.any(FalseClass, T::Array[String])) }
19
+ attr_accessor :verify_aud
20
+
21
+ sig { returns(T.any(T::Array[T.any(String, Regexp, T.proc.params(issuer: String).returns(T::Boolean))], FalseClass)) }
22
+ attr_accessor :verify_iss
23
+
24
+ sig do
25
+ returns(T.any(
26
+ T::Boolean,
27
+ T.proc.params(jti: String).returns(T::Boolean)
28
+ ))
29
+ end
30
+ attr_accessor :verify_jti
31
+
32
+ sig { void }
33
+ def initialize # rubocop:disable Metrics/AbcSize
34
+ @footer_serializer = T.let(Serializer::OptionalJson, Interface::Serializer)
35
+ @verify_exp = T.let(true, T::Boolean)
36
+ @verify_nbf = T.let(true, T::Boolean)
37
+ @verify_iat = T.let(true, T::Boolean)
38
+
39
+ @verify_iss = T.let(false, T.any(FalseClass,
40
+ T::Array[
41
+ T.any(String, Regexp, T.proc.params(issuer: String).returns(T::Boolean))
42
+ ]))
43
+
44
+ @verify_aud = T.let(false, T.any(FalseClass, T::Array[String]))
45
+
46
+ @verify_sub = T.let(false, T.any(FalseClass, String))
47
+
48
+ @verify_jti = T.let(false, T.any(
49
+ T::Boolean,
50
+ T.proc.params(jti: String).returns(T::Boolean)
51
+ ))
52
+ end
53
+
54
+ sig { returns(T::Hash[Symbol, T.untyped]) }
55
+ def to_h
56
+ {
57
+ verify_exp: verify_exp,
58
+ verify_nbf: verify_nbf,
59
+ verify_iss: verify_iss,
60
+ verify_iat: verify_iat,
61
+ verify_jti: verify_jti,
62
+ verify_aud: verify_aud,
63
+ verify_sub: verify_sub
64
+ }
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,18 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module Configuration
6
+ extend T::Sig
7
+
8
+ sig { params(blk: T.proc.params(config: Paseto::Configuration::Box).void).void }
9
+ def configure(&blk) # rubocop:disable Lint/UnusedMethodArgument
10
+ yield(config)
11
+ end
12
+
13
+ sig { returns(Paseto::Configuration::Box) }
14
+ def config
15
+ @config ||= T.let(Configuration::Box.new, T.nilable(Paseto::Configuration::Box))
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Paseto
5
+ module Interface
6
+ module ID
7
+ extend T::Sig
8
+ extend T::Helpers
9
+
10
+ abstract!
11
+
12
+ sig(:final) { params(type: String, paserk: String).returns(String) }
13
+ def encode(type, paserk)
14
+ header = "#{protocol.paserk_version}.#{type}."
15
+ d = protocol.digest("#{header}#{paserk}", digest_size: 33)
16
+ "#{header}#{Util.encode64(d)}"
17
+ end
18
+
19
+ sig { abstract.returns(Interface::Version) }
20
+ def protocol; end
21
+ end
22
+ end
23
+ end