class Gamecenter::Auth
Constants
- VERSION
Public Instance Methods
Get a public key certificate for given URL. Caches the results, depending on the configuration. @param [String] public_key_url the URL of the certificate to fetch @return [OpenSSL::X509::Certificate] certificate found at given URL or nil if there was an error
# File lib/gamecenter/auth.rb, line 148 def get_public_key_certificate(public_key_url) if @@cache_public_keys # caching is enabled cache = (@@_public_key_cache ||= {}) cert = cache[public_key_url] unless cert && cert.not_after > Time.now # no cache hit or certificate expired cache.delete public_key_url cert = request_public_key_certificate public_key_url available_entries = @@public_key_cache_entries - cache.size # check if there are free entries unless available_entries > 0 # there are not, randomly delete enough to make room for this certificate cache.keys.sample(available_entries.abs + 1).each { |key| cache.delete key } end cache[public_key_url] = cert end cert else # caching is disabled request_public_key_certificate public_key_url end end
Fetch a certificate from given URL. @param [String] public_key_url the URL to fetch the certificate from @return [OpenSSL::X509::Certificate] certificate found at given URL or nil if there was an error
# File lib/gamecenter/auth.rb, line 180 def request_public_key_certificate(public_key_url) uri = URI.parse public_key_url begin Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', open_timeout: @@request_public_key_open_timeout, read_timeout: @@request_public_key_read_timeout, ssl_timeout: @@request_public_key_ssl_timeout) do |http| request = Net::HTTP::Get.new uri.request_uri response = http.request request # Net::HTTPResponse object begin return OpenSSL::X509::Certificate.new(response.body) if response.body rescue OpenSSL::X509::CertificateError => e logger.error e end end rescue Net::OpenTimeout, Net::ReadTimeout, OpenSSL::SSL::SSLError => e logger.error e end nil end
Verifies the identity of the given player. Takes all return values from GameKit's generateIdentityVerificationSignatureWithCompletionHandler method. @see developer.apple.com/library/prerelease/ios/documentation/GameKit/Reference/GKLocalPlayer_Ref/index.html#//apple_ref/occ/instm/GKLocalPlayer/generateIdentityVerificationSignatureWithCompletionHandler: @param [String] player_id the playerID from the player to verify identity of @param [String] bundle_id the app's bundleID @param [String] public_key_url the publicKeyURL property returned from the GameKit framework @param [String] signature the signature property returned from the GameKit framework @param [String] salt the salt property returned from the GameKit framework @param [Integer] timestamp the timestamp property returned from the GameKit framework @return [Boolean] true if player could be verified, false if not
# File lib/gamecenter/auth.rb, line 81 def verify_player(player_id, bundle_id, public_key_url, signature, salt, timestamp) unless verify_public_key_url public_key_url logger.debug { "public key url invalid: #{public_key_url}" } return false end cert = get_public_key_certificate public_key_url unless cert logger.debug { "could not get certificate from: #{public_key_url}" } return false end if @@verify_issuer_certificate && !verify_public_key_certificate(cert) logger.debug { "failed verification of public key certificate from: #{public_key_url}" } return false end salt_decoded = @@base64_decode_salt ? Base64.decode64(salt) : salt payload = "#{player_id}#{bundle_id}#{[timestamp.to_i].pack('Q>')}#{salt_decoded}" signature_decoded = @@base64_decode_signature ? Base64.decode64(signature) : signature unless verify_signature cert, signature_decoded, payload logger.debug { "failed signature validation for player id #{player_id}, bundle id #{bundle_id}, timestamp #{timestamp}, salt #{salt} (decode: #{@@base64_decode_salt}), signature #{signature} (decode: #{@@base64_decode_signature}) with certificate from: #{public_key_url}" } return false end true end
Checks if given public key certificate can be verified with the CA certificate. @param [OpenSSL::X509::Certificate] public_key_cert a previously fetched public key certificate object @return [Boolean] true if certificate could be verified against the CA certificate, false if it couldn't
# File lib/gamecenter/auth.rb, line 126 def verify_public_key_certificate(public_key_cert) verified = public_key_cert.verify(@@ca_certificate.public_key) no_errors = OpenSSL.errors.empty? # this method has to be called always as it empties the OpenSSL error stack verified && no_errors end
Verifies that the public key url originates from one of Apple's secured servers. @param [String] public_key_url The publicKeyURL property returned from the GameKit framework @return [Boolean] true if url verification was successful, false if url fails verification
# File lib/gamecenter/auth.rb, line 111 def verify_public_key_url(public_key_url) url_ok = false begin uri = URI.parse public_key_url url_ok = uri.scheme == 'https' && !!(uri.host =~ /\.apple\.com$/i) rescue URI::InvalidURIError => e logger.error e end url_ok end
Verifies the signature of given payload with given public key certificate. @param [OpenSSL:X509::Certificate] public_key_cert a previously fetched public key certificate object @param [String] signature the signature to be verified @param [String] payload the payload to verify the signature for @return [Boolean] true if signature is valid for given certificate and payload, false if it isn't
# File lib/gamecenter/auth.rb, line 138 def verify_signature(public_key_cert, signature, payload) verified = public_key_cert.public_key.verify(OpenSSL::Digest::SHA256.new, signature, payload) no_errors = OpenSSL.errors.empty? # this method has to be called always as it empties the OpenSSL error stack verified && no_errors end
Private Instance Methods
# File lib/gamecenter/auth.rb, line 205 def logger @@logger ||= Logger.new(STDERR) end