Class: Fintoc::JWS

Inherits:
Object
  • Object
show all
Defined in:
lib/fintoc/jws.rb

Instance Method Summary collapse

Constructor Details

#initialize(private_key) ⇒ JWS

Returns a new instance of JWS.



8
9
10
11
12
13
14
# File 'lib/fintoc/jws.rb', line 8

def initialize(private_key)
  unless private_key.is_a?(OpenSSL::PKey::RSA)
    raise ArgumentError, 'private_key must be an OpenSSL::PKey::RSA instance'
  end

  @private_key = private_key
end

Instance Method Details

#generate_signature(raw_body) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/fintoc/jws.rb', line 16

def generate_signature(raw_body)
  body_string = raw_body.is_a?(Hash) ? raw_body.to_json : raw_body.to_s

  headers = {
    alg: 'RS256',
    nonce: SecureRandom.hex(16),
    ts: Time.now.to_i,
    crit: %w[ts nonce]
  }

  protected_base64 = base64url_encode(headers.to_json)
  payload_base64 = base64url_encode(body_string)
  signing_input = "#{protected_base64}.#{payload_base64}"

  signature = @private_key.sign(OpenSSL::Digest.new('SHA256'), signing_input)
  signature_base64 = base64url_encode(signature)

  "#{protected_base64}.#{signature_base64}"
end

#parse_signature(signature) ⇒ Object



36
37
38
39
40
41
42
43
44
45
# File 'lib/fintoc/jws.rb', line 36

def parse_signature(signature)
  protected_b64, signature_b64 = signature.split('.')

  {
    protected_headers: decode_protected_headers(protected_b64),
    signature_bytes: decode_signature(signature_b64),
    protected_b64: protected_b64,
    signature_b64: signature_b64
  }
end

#verify_signature(signature, payload) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/fintoc/jws.rb', line 47

def verify_signature(signature, payload)
  parsed = parse_signature(signature)

  # Reconstruct the signing input
  payload_json = payload.is_a?(Hash) ? payload.to_json : payload.to_s
  payload_b64 = base64url_encode(payload_json)
  signing_input = "#{parsed[:protected_b64]}.#{payload_b64}"

  # Verify with public key
  public_key = @private_key.public_key
  public_key.verify(OpenSSL::Digest.new('SHA256'), parsed[:signature_bytes], signing_input)
end