module FirebaseIdToken # Manage download and access of Google's x509 certificates. Keeps # certificates on a Redis namespace database. # # ## Download & Access Certificates # # It describes two ways to download it: {.request} and {.request!}. # The first will only do something when Redis certificates database is empty, # the second one will always request a new download to Google's API and # override the database with the response. # # It's important to note that when saving a set of certificates, it will also # set a Redis expiration time to match Google's API header `expires`. **After # this time went out, Redis will automatically delete those certificates.** # # *To know how many seconds left until the expiration you can use {.ttl}.* # # When comes to accessing it, you can either use {.present?} to check if # there's any data inside Redis certificates database or {.all} to obtain an # `Array` of current certificates. # # @example `.request` will only download once # FirebaseIdToken::Certificates.request # Downloads certificates. # FirebaseIdToken::Certificates.request # Won't do anything. # FirebaseIdToken::Certificates.request # Won't do anything either. # # @example `.request!` will download always # FirebaseIdToken::Certificates.request # Downloads certificates. # FirebaseIdToken::Certificates.request! # Downloads certificates. # FirebaseIdToken::Certificates.request! # Downloads certificates. # class Certificates # A Redis instance. attr_reader :redis # Certificates saved in the Redis (JSON `String` or `nil`). attr_reader :local_certs # Google's x509 certificates API URL. URL = 'https://www.googleapis.com/robot/v1/metadata/x509/'\ 'securetoken@system.gserviceaccount.com' # Calls {.request!} only if there are no certificates on Redis. It will # return `nil` otherwise. # # It will raise {Exceptions::CertificatesRequestError} if the request # fails or {Exceptions::CertificatesTtlError} when Google responds with a # low TTL, check out {.request!} for more info. # # @return [nil, Hash] # @see Certificates.request! def self.request new.request end # Triggers a HTTPS request to Google's x509 certificates API. If it # responds with a status `200 OK`, saves the request body into Redis and # returns it as a `Hash`. # # Otherwise it will raise a {Exceptions::CertificatesRequestError}. # # This is really rare to happen, but Google may respond with a low TTL # certificate. This is a `SecurityError` and will raise a # {Exceptions::CertificatesTtlError}. You are mostly like to never face it. # @return [Hash] def self.request! new.request! end # @deprecated Use only `request!` in favor of Ruby conventions. # It will raise a warning. Kept for compatibility. # @see Certificates.request! def self.request_anyway warn 'WARNING: FirebaseIdToken::Certificates.request_anyway is '\ 'deprecated. Use FirebaseIdToken::Certificates.request! instead.' new.request! end # Returns `true` if there's certificates data on Redis, `false` otherwise. # @example # FirebaseIdToken::Certificates.present? #=> false # FirebaseIdToken::Certificates.request # FirebaseIdToken::Certificates.present? #=> true def self.present? ! new.local_certs.empty? end # Returns an array of hashes, each hash is a single `{key => value}` pair # containing the certificate KID `String` as key and a # `OpenSSL::X509::Certificate` object of the respective certificate as # value. Returns a empty `Array` when there's no certificates data on # Redis. # @return [Array] # @example # FirebaseIdToken::Certificates.request # certs = FirebaseIdToken::Certificates.all # certs.first #=> {"1d6d01c7[...]" => # OpenSSL::X509::Certificate.new(cert) } } end # Returns a `OpenSSL::X509::Certificate` object of the requested Key ID # (KID) if there's one. Returns `nil` otherwise. # # It will raise a {Exceptions::NoCertificatesError} if the Redis # certificates database is empty. # @param [String] kid Key ID # @return [nil, OpenSSL::X509::Certificate] # @example # FirebaseIdToken::Certificates.request # cert = FirebaseIdToken::Certificates.find "1d6d01f4w7d54c7[...]" # #=> 3600 ttl else raise Exceptions::CertificatesTtlError end end end end