Class: IAPServer::JWTTools

Inherits:
Object
  • Object
show all
Defined in:
lib/iap/jwttools.rb

Class Method Summary collapse

Class Method Details

.generateObject



9
10
11
12
13
14
15
16
17
# File 'lib/iap/jwttools.rb', line 9

def self.generate
	config = IAPServer::AppStoreConfig.default_config
	raise "获取秘钥信息失败,请检查。" if config.nil?
	
	key, kid, iss, bid = config['key'], config['kid'], config['iss'], config['bid']
	# fix key
	key = key.split("\\n").join("\n") if key.include?("\\n")
	generate_token(key, kid, iss, bid)
end

.generate_token(key, kid, iss, bid) ⇒ Object

秘钥串、秘钥ID、Issuer ID、bundle id



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/iap/jwttools.rb', line 20

def self.generate_token(key, kid, iss, bid)
	# JWT Header
	header = {
		"alg": "ES256", # 固定值
		"kid": kid, # private key ID from App Store Connect
		"typ": "JWT" # 固定值
	}

	iat = Time.new
	# JWT Payload
	payload = {
		"iss": iss, # Your issuer ID from the Keys page in App Store Connect
		"aud": "appstoreconnect-v1", # 固定值
		"iat": iat.to_i, # 令牌生成时间,UNIX时间单位,秒
		"exp": iat.to_i + 60 * 60, # 令牌失效时间,60 minutes timestamp
		"nonce": UUIDTools::UUID.timestamp_create.to_s, # An arbitrary number you create and use only once
		"bid": bid # Your app's bundle ID
	}

	ecdsa_key = OpenSSL::PKey::EC.new key
	# JWT token
	token = JWT.encode payload, ecdsa_key, algorithm='ES256', header_fields=header
	token
end

.good_signature(jws_token) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/iap/jwttools.rb', line 45

def self.good_signature(jws_token)
    realpath = File.expand_path("#{File.dirname(__FILE__)}/../../assets/AppleRootCA-G3.cer")
    raw = File.read "#{realpath}"
    apple_root_cert = OpenSSL::X509::Certificate.new(raw)

    parts = jws_token.split(".")
    decoded_parts = parts.map { |part| Base64.decode64(part) }
    header = JSON.parse(decoded_parts[0])
    # puts "Header:#{decoded_parts[0]}"
    # puts "Payload:#{decoded_parts[1]}"

    cert_chain =  header["x5c"].map { |part| OpenSSL::X509::Certificate.new(Base64.decode64(part))}
    return false unless cert_chain.last == apple_root_cert

    for n in 0..(cert_chain.count - 2)
      return false unless cert_chain[n].verify(cert_chain[n+1].public_key)
    end

    begin
      decoded_token = JWT.decode(jws_token, cert_chain[0].public_key, true, { algorithms: ['ES256'] })
      !decoded_token.nil?
    rescue JWT::JWKError
      false
    rescue JWT::DecodeError
      false
    end
end

.header(jws_token) ⇒ Object



79
80
81
82
83
# File 'lib/iap/jwttools.rb', line 79

def self.header(jws_token)
    parts = jws_token.split(".")
    decoded_parts = parts.map { |part| Base64.decode64(part) }
    decoded_parts[0]
end

.payload(jws_token) ⇒ Object



73
74
75
76
77
# File 'lib/iap/jwttools.rb', line 73

def self.payload(jws_token)
    parts = jws_token.split(".")
    decoded_parts = parts.map { |part| Base64.decode64(part) }
    decoded_parts[1]
end