mobile_id 0.0.2 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +20 -0
 - data/MIT-LICENSE +22 -0
 - data/README.md +133 -0
 - data/lib/mobile_id.rb +5 -145
 - data/lib/mobile_id/auth.rb +147 -0
 - data/lib/mobile_id/cert.rb +93 -0
 - data/lib/mobile_id/certs/EE_Certification_Centre_Root_CA.pem.crt +24 -0
 - data/lib/mobile_id/certs/ESTEID-SK_2015.pem.crt +37 -0
 - data/lib/mobile_id/certs/TEST_of_EE_Certification_Centre_Root_CA.pem.crt +24 -0
 - data/lib/mobile_id/certs/TEST_of_ESTEID-SK_2015.pem.crt +37 -0
 - data/lib/mobile_id/locales/en.yml +10 -0
 - data/lib/mobile_id/locales/et.yml +10 -0
 - data/lib/mobile_id/locales/ru.yml +10 -0
 - data/lib/mobile_id/railtie.rb +13 -0
 - metadata +14 -1
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: ac13ee4d2a254bb0b64473c0dbbdd8e26a42dc60dcb3dfdbbbcd6c52d35b2826
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: c01bc3c9e51a8795efe74d14cdb3426645a445cbe8f5cd750fce34795e4f1341
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 9b4f3bfe1608f051a02814ab6299320804ffcbdcb12da9e3aaae232050e6f24af997636668efbf578e80ad80d6a7c76319444695c97b80de30a7b585d05eeace
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 96c9db3d18d630e249772b560dfdd8d6d52974bc6bf968efbee15ae3d5eeba86db88b91724bbe2950ed180ac72c781d805f8e94be1b3d1ee4f7a02ec6526c078
         
     | 
    
        data/CHANGELOG.md
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Release 0.0.7
         
     | 
| 
      
 2 
     | 
    
         
            +
            * Cert cleanup
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Release 0.0.6
         
     | 
| 
      
 5 
     | 
    
         
            +
            * Cert path fix
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Release 0.0.5
         
     | 
| 
      
 8 
     | 
    
         
            +
            * Added user certificate validation 
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            Release 0.0.4
         
     | 
| 
      
 11 
     | 
    
         
            +
            * Refactored MobileId to MobileId::Auth
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            Release 0.0.3
         
     | 
| 
      
 14 
     | 
    
         
            +
            * Gemspec update
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            Release 0.0.2
         
     | 
| 
      
 17 
     | 
    
         
            +
            * Readme update
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            Release 0.0.1
         
     | 
| 
      
 20 
     | 
    
         
            +
            * Init
         
     | 
    
        data/MIT-LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2019-2020, Priit Tark, priit@gitlab.eu
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person
         
     | 
| 
      
 4 
     | 
    
         
            +
            obtaining a copy of this software and associated documentation
         
     | 
| 
      
 5 
     | 
    
         
            +
            files (the "Software"), to deal in the Software without
         
     | 
| 
      
 6 
     | 
    
         
            +
            restriction, including without limitation the rights to use,
         
     | 
| 
      
 7 
     | 
    
         
            +
            copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 8 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the
         
     | 
| 
      
 9 
     | 
    
         
            +
            Software is furnished to do so, subject to the following
         
     | 
| 
      
 10 
     | 
    
         
            +
            conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 13 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 16 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
         
     | 
| 
      
 17 
     | 
    
         
            +
            OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 18 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
         
     | 
| 
      
 19 
     | 
    
         
            +
            HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
         
     | 
| 
      
 20 
     | 
    
         
            +
            WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
         
     | 
| 
      
 21 
     | 
    
         
            +
            FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
         
     | 
| 
      
 22 
     | 
    
         
            +
            OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,133 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # MobileId::Ruby::Gem
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Estonia Mobile ID authentication, more info at https://www.id.ee/en/
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 10 
     | 
    
         
            +
            gem 'mobile_id'
         
     | 
| 
      
 11 
     | 
    
         
            +
            ```
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                $ gem install mobile_id
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ## Test usage
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            Execute irb:
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                $ bundle exec irb
         
     | 
| 
      
 26 
     | 
    
         
            +
                irb(main):001:0> require 'mobile_id'
         
     | 
| 
      
 27 
     | 
    
         
            +
                => true
         
     | 
| 
      
 28 
     | 
    
         
            +
                irb(main):002:0> @mid = MobileId::Auth.new(live: false)
         
     | 
| 
      
 29 
     | 
    
         
            +
                => #<MobileId::Auth:0x000055ac4cb25630 @url="https://tsp.demo.sk.ee/mid-api", @uuid="00000000-0000-0000-0000-000000000000", @name="DEMO", @hash="two+e7UMoFCAXHo8q9AnWqSC58Hhil74RowY8Gg9xQY=">
         
     | 
| 
      
 30 
     | 
    
         
            +
                irb(main):003:0> auth = @mid.authenticate!(phone: '00000766', personal_code: '60001019906')
         
     | 
| 
      
 31 
     | 
    
         
            +
                => {"session_id"=>"34e7eff0-691b-4fad-9798-8db680587b18", "phone"=>"00000766", "phone_calling_code"=>"+372"}
         
     | 
| 
      
 32 
     | 
    
         
            +
                irb(main):004:0> verify = @mid.verify!(auth)
         
     | 
| 
      
 33 
     | 
    
         
            +
                => {"personal_code"=>"60001019906", "first_name"=>"MARY ÄNN", "last_name"=>"O’CONNEŽ-ŠUSLIK TESTNUMBER", "phone"=>"00000766", "phone_calling_code"=>"+372", "auth_provider"=>"mobileid"}
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            You get verified attributes: personal_code, first_name, last_name, phone, phone_calling_code, auth_provider
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            ## Live usage
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            For live usage, add your relyingPartyUUID (RPUUID) and relyingPartyName what you get from https://www.sk.ee
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 43 
     | 
    
         
            +
                @mid = MobileId::Auth.new(live: true, uuid: "39e7eff0-241b-4fad-2798-9db680587b20", name: 'My service name')
         
     | 
| 
      
 44 
     | 
    
         
            +
            ```
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            Rails with Devise example controller:
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 49 
     | 
    
         
            +
            class MobileSessionsController < ApplicationController
         
     | 
| 
      
 50 
     | 
    
         
            +
              include Devise::Controllers::Helpers
         
     | 
| 
      
 51 
     | 
    
         
            +
              skip_authorization_check only: [:new, :show, :create, :update]
         
     | 
| 
      
 52 
     | 
    
         
            +
              before_action :init_mobile_id, only: [:create, :update]
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
              def new
         
     | 
| 
      
 55 
     | 
    
         
            +
                @user = User.new
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              # makes Mobile ID authentication
         
     | 
| 
      
 59 
     | 
    
         
            +
              def create
         
     | 
| 
      
 60 
     | 
    
         
            +
                session[:auth] = @mid.authenticate!(phone: params[:phone], personal_code: params[:personal_code])
         
     | 
| 
      
 61 
     | 
    
         
            +
                render :show, locals: { verification_code: @mid.verification_code }
         
     | 
| 
      
 62 
     | 
    
         
            +
              rescue MobileId::Error => e
         
     | 
| 
      
 63 
     | 
    
         
            +
                render :error, locals: { message: e }
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              # verifices Mobile ID user
         
     | 
| 
      
 67 
     | 
    
         
            +
              def update
         
     | 
| 
      
 68 
     | 
    
         
            +
                session[:auth] = @mid.verify!(session[:auth])
         
     | 
| 
      
 69 
     | 
    
         
            +
                find_or_create_user_and_redirect(personal_code: @mid.personal_code)
         
     | 
| 
      
 70 
     | 
    
         
            +
              rescue MobileId::Error => e
         
     | 
| 
      
 71 
     | 
    
         
            +
                render :error, locals: { message: e }
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              private
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
              def init_mobile_id
         
     | 
| 
      
 77 
     | 
    
         
            +
                @mid = MobileId.new(live: true, uuid: ENV['sk_mid_uuid'], name: ENV['sk_mid_name'])
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              # It's pure your system business logic what to do here with validated user attributes, example code:
         
     | 
| 
      
 81 
     | 
    
         
            +
              def find_or_create_user_and_redirect(personal_code:)
         
     | 
| 
      
 82 
     | 
    
         
            +
                @user = User.find_by(personal_code: personal_code)
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                # bind currently present email only account with mobile-id
         
     | 
| 
      
 85 
     | 
    
         
            +
                if @user.nil? && current_user&.confirmed_email_only_account?
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @user = current_user 
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @user.personal_code = personal_code
         
     | 
| 
      
 88 
     | 
    
         
            +
                  @user.save!
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                return redirect_to new_omniuser_url, notice: t(:finish_setup) if @user.nil? || @user.new_record?
         
     | 
| 
      
 92 
     | 
    
         
            +
                return redirect_to root_url, alert: t(:unlock_info) if @user.access_locked?
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                if @user.valid? && @user.confirmed_at
         
     | 
| 
      
 95 
     | 
    
         
            +
                  # overwrite name changes
         
     | 
| 
      
 96 
     | 
    
         
            +
                  @user.first_name = session[:auth]['first_name'] if session[:auth]['first_name'].present?
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @user.last_name  = session[:auth]['last_name']  if session[:auth]['last_name'].present?
         
     | 
| 
      
 98 
     | 
    
         
            +
                  @user.save! if @user.changed?
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  sign_in_and_redirect(@user, notice: t('devise.sessions.signed_in'))
         
     | 
| 
      
 101 
     | 
    
         
            +
                else
         
     | 
| 
      
 102 
     | 
    
         
            +
                  redirect_to edit_omniuser_url(@user), notice: t('devise.failure.unconfirmed')
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
              end
         
     | 
| 
      
 105 
     | 
    
         
            +
            end
         
     | 
| 
      
 106 
     | 
    
         
            +
            ```
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            ## Development
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            After checking out the repo, run `bundle` to install dependencies. For testing code, run `rspec`
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
            ## Contributors
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
            * Priit Tark
         
     | 
| 
      
 115 
     | 
    
         
            +
            * Andri Möll for pointing out user signature issue
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/gitlabeu/mobile_id
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            ## Roadmap
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            * Auth signature validation
         
     | 
| 
      
 124 
     | 
    
         
            +
            * Document sign
         
     | 
| 
      
 125 
     | 
    
         
            +
            * Rails generators
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
            ## License
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
            ## Sponsors
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
            Gem development and testing is sponsored by [GiTLAB](https://gitlab.eu).
         
     | 
    
        data/lib/mobile_id.rb
    CHANGED
    
    | 
         @@ -11,151 +11,11 @@ else 
     | 
|
| 
       11 
11 
     | 
    
         
             
              I18n.load_path << Dir[File.expand_path("lib/mobile_id/locales") + "/*.yml"]
         
     | 
| 
       12 
12 
     | 
    
         
             
            end
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
      
 14 
     | 
    
         
            +
            module MobileId
         
     | 
| 
       15 
15 
     | 
    
         
             
              class Error < StandardError; end
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
               
     | 
| 
       18 
     | 
    
         
            -
              LIVE_URL = "https://mid.sk.ee/mid-api"
         
     | 
| 
       19 
     | 
    
         
            -
              TEST_URL = "https://tsp.demo.sk.ee/mid-api"
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
              TEST_UUID  = "00000000-0000-0000-0000-000000000000"
         
     | 
| 
       22 
     | 
    
         
            -
              TEST_NAME  = "DEMO"
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
              attr_accessor :url, :uuid, :name, :hash, :cert, :cert_subject
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
              def initialize(live:, uuid: nil, name: nil)
         
     | 
| 
       27 
     | 
    
         
            -
                self.url = live == true ? LIVE_URL : TEST_URL
         
     | 
| 
       28 
     | 
    
         
            -
                self.uuid = live == true ? uuid : TEST_UUID
         
     | 
| 
       29 
     | 
    
         
            -
                self.name = live == true ? name : TEST_NAME
         
     | 
| 
       30 
     | 
    
         
            -
                self.hash = Digest::SHA256.base64digest(SecureRandom.uuid)
         
     | 
| 
       31 
     | 
    
         
            -
              end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
              def authenticate!(phone_calling_code: nil, phone:, personal_code:, language: nil, display_text: nil)
         
     | 
| 
       34 
     | 
    
         
            -
                phone_calling_code ||= '+372'
         
     | 
| 
       35 
     | 
    
         
            -
                full_phone = "#{phone_calling_code}#{phone}"
         
     | 
| 
       36 
     | 
    
         
            -
                language ||= 
         
     | 
| 
       37 
     | 
    
         
            -
                  case I18n.locale
         
     | 
| 
       38 
     | 
    
         
            -
                  when :et
         
     | 
| 
       39 
     | 
    
         
            -
                    display_text ||= 'Autentimine' 
         
     | 
| 
       40 
     | 
    
         
            -
                    'EST'
         
     | 
| 
       41 
     | 
    
         
            -
                  when :ru
         
     | 
| 
       42 
     | 
    
         
            -
                    display_text ||= 'Аутентификация' 
         
     | 
| 
       43 
     | 
    
         
            -
                    'RUS'
         
     | 
| 
       44 
     | 
    
         
            -
                  else
         
     | 
| 
       45 
     | 
    
         
            -
                    display_text ||= 'Authentication' 
         
     | 
| 
       46 
     | 
    
         
            -
                    'ENG'
         
     | 
| 
       47 
     | 
    
         
            -
                  end
         
     | 
| 
       48 
     | 
    
         
            -
                
         
     | 
| 
       49 
     | 
    
         
            -
                options = {
         
     | 
| 
       50 
     | 
    
         
            -
                  headers: {
         
     | 
| 
       51 
     | 
    
         
            -
                    "Content-Type": "application/json"
         
     | 
| 
       52 
     | 
    
         
            -
                  },
         
     | 
| 
       53 
     | 
    
         
            -
                  query: {},
         
     | 
| 
       54 
     | 
    
         
            -
                  body: {
         
     | 
| 
       55 
     | 
    
         
            -
                    relyingPartyUUID: uuid,
         
     | 
| 
       56 
     | 
    
         
            -
                    relyingPartyName: name,
         
     | 
| 
       57 
     | 
    
         
            -
                    phoneNumber: full_phone.to_s.strip,
         
     | 
| 
       58 
     | 
    
         
            -
                    nationalIdentityNumber: personal_code.to_s.strip,
         
     | 
| 
       59 
     | 
    
         
            -
                    hash: hash,
         
     | 
| 
       60 
     | 
    
         
            -
                    hashType: 'SHA256',
         
     | 
| 
       61 
     | 
    
         
            -
                    language: language,
         
     | 
| 
       62 
     | 
    
         
            -
                    displayText: display_text,
         
     | 
| 
       63 
     | 
    
         
            -
                    displayTextFormat: 'GSM-7' # or "UCS-2”
         
     | 
| 
       64 
     | 
    
         
            -
                  }.to_json
         
     | 
| 
       65 
     | 
    
         
            -
                }
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                response = HTTParty.post(url + '/authentication', options)
         
     | 
| 
       68 
     | 
    
         
            -
                raise Error, "#{I18n.t('mobile_id.some_error')} #{response}" unless response.code == 200
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                ActiveSupport::HashWithIndifferentAccess.new(
         
     | 
| 
       71 
     | 
    
         
            -
                  session_id: response['sessionID'],
         
     | 
| 
       72 
     | 
    
         
            -
                  phone: phone,
         
     | 
| 
       73 
     | 
    
         
            -
                  phone_calling_code: phone_calling_code
         
     | 
| 
       74 
     | 
    
         
            -
                )
         
     | 
| 
       75 
     | 
    
         
            -
              end
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
              def verify!(auth)
         
     | 
| 
       78 
     | 
    
         
            -
                long_poll!(session_id: auth['session_id'])
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
                ActiveSupport::HashWithIndifferentAccess.new(
         
     | 
| 
       81 
     | 
    
         
            -
                  personal_code: personal_code,
         
     | 
| 
       82 
     | 
    
         
            -
                  first_name: first_name,
         
     | 
| 
       83 
     | 
    
         
            -
                  last_name: last_name,
         
     | 
| 
       84 
     | 
    
         
            -
                  phone: auth['phone'],
         
     | 
| 
       85 
     | 
    
         
            -
                  phone_calling_code: auth['phone_calling_code'],
         
     | 
| 
       86 
     | 
    
         
            -
                  auth_provider: 'mobileid' # User::MOBILEID
         
     | 
| 
       87 
     | 
    
         
            -
                )
         
     | 
| 
       88 
     | 
    
         
            -
              end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
              def long_poll!(session_id:)
         
     | 
| 
       91 
     | 
    
         
            -
                response = HTTParty.get(url + "/authentication/session/#{session_id}")
         
     | 
| 
       92 
     | 
    
         
            -
                raise Error, "#{I18n.t('mobile_id.some_error')} #{response.code} #{response}" if response.code != 200
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                if response['state'] == 'COMPLETE' && response['result'] != 'OK'
         
     | 
| 
       95 
     | 
    
         
            -
                  message = 
         
     | 
| 
       96 
     | 
    
         
            -
                    case response['result']
         
     | 
| 
       97 
     | 
    
         
            -
                    when "TIMEOUT"
         
     | 
| 
       98 
     | 
    
         
            -
                      I18n.t('mobile_id.timeout')
         
     | 
| 
       99 
     | 
    
         
            -
                    when "NOT_MID_CLIENT"
         
     | 
| 
       100 
     | 
    
         
            -
                      I18n.t('mobile_id.user_is_not_mobile_id_client')
         
     | 
| 
       101 
     | 
    
         
            -
                    when "USER_CANCELLED"
         
     | 
| 
       102 
     | 
    
         
            -
                      I18n.t('mobile_id.user_cancelled')
         
     | 
| 
       103 
     | 
    
         
            -
                    when "SIGNATURE_HASH_MISMATCH"
         
     | 
| 
       104 
     | 
    
         
            -
                      I18n.t('mobile_id.signature_hash_mismatch')
         
     | 
| 
       105 
     | 
    
         
            -
                    when "PHONE_ABSENT"
         
     | 
| 
       106 
     | 
    
         
            -
                      I18n.t('mobile_id.phone_absent')
         
     | 
| 
       107 
     | 
    
         
            -
                    when "DELIVERY_ERROR"
         
     | 
| 
       108 
     | 
    
         
            -
                      I18n.t('mobile_id.delivery_error')
         
     | 
| 
       109 
     | 
    
         
            -
                    when "SIM_ERROR"
         
     | 
| 
       110 
     | 
    
         
            -
                      I18n.t('mobile_id.sim_error')
         
     | 
| 
       111 
     | 
    
         
            -
                    end
         
     | 
| 
       112 
     | 
    
         
            -
                  raise Error, message
         
     | 
| 
       113 
     | 
    
         
            -
                end
         
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
                self.cert = OpenSSL::X509::Certificate.new(Base64.decode64(response['cert']))
         
     | 
| 
       116 
     | 
    
         
            -
                self.cert_subject = build_cert_subject
         
     | 
| 
       117 
     | 
    
         
            -
                cert
         
     | 
| 
       118 
     | 
    
         
            -
              end
         
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
              def verification_code
         
     | 
| 
       121 
     | 
    
         
            -
                format("%04d", (Digest::SHA2.new(256).digest(Base64.decode64(hash))[-2..-1].unpack1('n') % 10000))
         
     | 
| 
       122 
     | 
    
         
            -
              end
         
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
              def given_name
         
     | 
| 
       125 
     | 
    
         
            -
                cert_subject["GN"].tr(",", " ")
         
     | 
| 
       126 
     | 
    
         
            -
              end
         
     | 
| 
       127 
     | 
    
         
            -
              alias first_name given_name
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
              def surname
         
     | 
| 
       130 
     | 
    
         
            -
                cert_subject["SN"].tr(",", " ")
         
     | 
| 
       131 
     | 
    
         
            -
              end
         
     | 
| 
       132 
     | 
    
         
            -
              alias last_name surname
         
     | 
| 
       133 
     | 
    
         
            -
              
         
     | 
| 
       134 
     | 
    
         
            -
              def country
         
     | 
| 
       135 
     | 
    
         
            -
                cert_subject["C"].tr(",", " ")
         
     | 
| 
       136 
     | 
    
         
            -
              end
         
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
              def common_name
         
     | 
| 
       139 
     | 
    
         
            -
                cert_subject["CN"]
         
     | 
| 
       140 
     | 
    
         
            -
              end
         
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
              def organizational_unit
         
     | 
| 
       143 
     | 
    
         
            -
                cert_subject["OU"]
         
     | 
| 
       144 
     | 
    
         
            -
              end
         
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
              def serial_number
         
     | 
| 
       147 
     | 
    
         
            -
                cert_subject["serialNumber"]
         
     | 
| 
       148 
     | 
    
         
            -
              end
         
     | 
| 
       149 
     | 
    
         
            -
              alias personal_code serial_number
         
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
              private
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
              def build_cert_subject
         
     | 
| 
       154 
     | 
    
         
            -
                self.cert_subject = cert.subject.to_utf8.split(/(?<!\\)\,+/).each_with_object({}) do |c, result|
         
     | 
| 
       155 
     | 
    
         
            -
                  next unless c.include?("=")
         
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
     | 
    
         
            -
                  key, val = c.split("=")
         
     | 
| 
       158 
     | 
    
         
            -
                  result[key] = val
         
     | 
| 
       159 
     | 
    
         
            -
                end
         
     | 
| 
       160 
     | 
    
         
            -
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
              LOCALES = [:en, :et, :ru]
         
     | 
| 
       161 
18 
     | 
    
         
             
            end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            require 'mobile_id/cert'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'mobile_id/auth'
         
     | 
| 
         @@ -0,0 +1,147 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module MobileId
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Auth
         
     | 
| 
      
 5 
     | 
    
         
            +
                # API documentation https://github.com/SK-EID/MID
         
     | 
| 
      
 6 
     | 
    
         
            +
                LIVE_URL = "https://mid.sk.ee/mid-api"
         
     | 
| 
      
 7 
     | 
    
         
            +
                TEST_URL = "https://tsp.demo.sk.ee/mid-api"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                TEST_UUID  = "00000000-0000-0000-0000-000000000000"
         
     | 
| 
      
 10 
     | 
    
         
            +
                TEST_NAME  = "DEMO"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                attr_accessor :url, :uuid, :name, :doc, :hash, :user_cert, :live
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def initialize(live:, uuid: nil, name: nil)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  self.url = live == true ? LIVE_URL : TEST_URL
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.uuid = live == true ? uuid : TEST_UUID
         
     | 
| 
      
 17 
     | 
    
         
            +
                  self.name = live == true ? name : TEST_NAME
         
     | 
| 
      
 18 
     | 
    
         
            +
                  self.live = live
         
     | 
| 
      
 19 
     | 
    
         
            +
                  init_doc(SecureRandom.uuid)
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def init_doc(doc)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  self.doc = doc
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  self.hash = Digest::SHA256.base64digest(self.doc)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def authenticate!(phone_calling_code: nil, phone:, personal_code:, language: nil, display_text: nil)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  phone_calling_code ||= '+372'
         
     | 
| 
      
 30 
     | 
    
         
            +
                  full_phone = "#{phone_calling_code}#{phone}"
         
     | 
| 
      
 31 
     | 
    
         
            +
                  language ||= 
         
     | 
| 
      
 32 
     | 
    
         
            +
                    case I18n.locale
         
     | 
| 
      
 33 
     | 
    
         
            +
                    when :et
         
     | 
| 
      
 34 
     | 
    
         
            +
                      display_text ||= 'Autentimine' 
         
     | 
| 
      
 35 
     | 
    
         
            +
                      'EST'
         
     | 
| 
      
 36 
     | 
    
         
            +
                    when :ru
         
     | 
| 
      
 37 
     | 
    
         
            +
                      display_text ||= 'Аутентификация' 
         
     | 
| 
      
 38 
     | 
    
         
            +
                      'RUS'
         
     | 
| 
      
 39 
     | 
    
         
            +
                    else
         
     | 
| 
      
 40 
     | 
    
         
            +
                      display_text ||= 'Authentication' 
         
     | 
| 
      
 41 
     | 
    
         
            +
                      'ENG'
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  
         
     | 
| 
      
 44 
     | 
    
         
            +
                  options = {
         
     | 
| 
      
 45 
     | 
    
         
            +
                    headers: {
         
     | 
| 
      
 46 
     | 
    
         
            +
                      "Content-Type": "application/json"
         
     | 
| 
      
 47 
     | 
    
         
            +
                    },
         
     | 
| 
      
 48 
     | 
    
         
            +
                    query: {},
         
     | 
| 
      
 49 
     | 
    
         
            +
                    body: {
         
     | 
| 
      
 50 
     | 
    
         
            +
                      relyingPartyUUID: uuid,
         
     | 
| 
      
 51 
     | 
    
         
            +
                      relyingPartyName: name,
         
     | 
| 
      
 52 
     | 
    
         
            +
                      phoneNumber: full_phone.to_s.strip,
         
     | 
| 
      
 53 
     | 
    
         
            +
                      nationalIdentityNumber: personal_code.to_s.strip,
         
     | 
| 
      
 54 
     | 
    
         
            +
                      hash: hash,
         
     | 
| 
      
 55 
     | 
    
         
            +
                      hashType: 'SHA256',
         
     | 
| 
      
 56 
     | 
    
         
            +
                      language: language,
         
     | 
| 
      
 57 
     | 
    
         
            +
                      displayText: display_text,
         
     | 
| 
      
 58 
     | 
    
         
            +
                      displayTextFormat: 'GSM-7' # or "UCS-2”
         
     | 
| 
      
 59 
     | 
    
         
            +
                    }.to_json
         
     | 
| 
      
 60 
     | 
    
         
            +
                  }
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  response = HTTParty.post(url + '/authentication', options)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  raise Error, "#{I18n.t('mobile_id.some_error')} #{response}" unless response.code == 200
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  ActiveSupport::HashWithIndifferentAccess.new(
         
     | 
| 
      
 66 
     | 
    
         
            +
                    session_id: response['sessionID'],
         
     | 
| 
      
 67 
     | 
    
         
            +
                    phone: phone,
         
     | 
| 
      
 68 
     | 
    
         
            +
                    phone_calling_code: phone_calling_code,
         
     | 
| 
      
 69 
     | 
    
         
            +
                    doc: doc
         
     | 
| 
      
 70 
     | 
    
         
            +
                  )
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def verify!(auth)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  long_poll!(session_id: auth['session_id'], doc: auth['doc'])
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  ActiveSupport::HashWithIndifferentAccess.new(
         
     | 
| 
      
 77 
     | 
    
         
            +
                    personal_code: personal_code,
         
     | 
| 
      
 78 
     | 
    
         
            +
                    first_name: first_name,
         
     | 
| 
      
 79 
     | 
    
         
            +
                    last_name: last_name,
         
     | 
| 
      
 80 
     | 
    
         
            +
                    phone: auth['phone'],
         
     | 
| 
      
 81 
     | 
    
         
            +
                    phone_calling_code: auth['phone_calling_code'],
         
     | 
| 
      
 82 
     | 
    
         
            +
                    auth_provider: 'mobileid' # User::MOBILEID
         
     | 
| 
      
 83 
     | 
    
         
            +
                  )
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def long_poll!(session_id:, doc:)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  response = HTTParty.get(url + "/authentication/session/#{session_id}")
         
     | 
| 
      
 88 
     | 
    
         
            +
                  raise Error, "#{I18n.t('mobile_id.some_error')} #{response.code} #{response}" if response.code != 200
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  if response['state'] == 'COMPLETE' && response['result'] != 'OK'
         
     | 
| 
      
 91 
     | 
    
         
            +
                    message = 
         
     | 
| 
      
 92 
     | 
    
         
            +
                      case response['result']
         
     | 
| 
      
 93 
     | 
    
         
            +
                      when "TIMEOUT"
         
     | 
| 
      
 94 
     | 
    
         
            +
                        I18n.t('mobile_id.timeout')
         
     | 
| 
      
 95 
     | 
    
         
            +
                      when "NOT_MID_CLIENT"
         
     | 
| 
      
 96 
     | 
    
         
            +
                        I18n.t('mobile_id.user_is_not_mobile_id_client')
         
     | 
| 
      
 97 
     | 
    
         
            +
                      when "USER_CANCELLED"
         
     | 
| 
      
 98 
     | 
    
         
            +
                        I18n.t('mobile_id.user_cancelled')
         
     | 
| 
      
 99 
     | 
    
         
            +
                      when "SIGNATURE_HASH_MISMATCH"
         
     | 
| 
      
 100 
     | 
    
         
            +
                        I18n.t('mobile_id.signature_hash_mismatch')
         
     | 
| 
      
 101 
     | 
    
         
            +
                      when "PHONE_ABSENT"
         
     | 
| 
      
 102 
     | 
    
         
            +
                        I18n.t('mobile_id.phone_absent')
         
     | 
| 
      
 103 
     | 
    
         
            +
                      when "DELIVERY_ERROR"
         
     | 
| 
      
 104 
     | 
    
         
            +
                        I18n.t('mobile_id.delivery_error')
         
     | 
| 
      
 105 
     | 
    
         
            +
                      when "SIM_ERROR"
         
     | 
| 
      
 106 
     | 
    
         
            +
                        I18n.t('mobile_id.sim_error')
         
     | 
| 
      
 107 
     | 
    
         
            +
                      end
         
     | 
| 
      
 108 
     | 
    
         
            +
                    raise Error, message
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                  @user_cert = MobileId::Cert.new(response['cert'], live: live)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  @user_cert.verify_signature!(response['signature']['value'], doc)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  self.user_cert = @user_cert
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                def verification_code
         
     | 
| 
      
 117 
     | 
    
         
            +
                  format("%04d", (Digest::SHA2.new(256).digest(Base64.decode64(hash))[-2..-1].unpack1('n') % 10000))
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                def given_name
         
     | 
| 
      
 121 
     | 
    
         
            +
                  user_cert.given_name
         
     | 
| 
      
 122 
     | 
    
         
            +
                end
         
     | 
| 
      
 123 
     | 
    
         
            +
                alias first_name given_name
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                def surname
         
     | 
| 
      
 126 
     | 
    
         
            +
                  user_cert.surname
         
     | 
| 
      
 127 
     | 
    
         
            +
                end
         
     | 
| 
      
 128 
     | 
    
         
            +
                alias last_name surname
         
     | 
| 
      
 129 
     | 
    
         
            +
                
         
     | 
| 
      
 130 
     | 
    
         
            +
                def country
         
     | 
| 
      
 131 
     | 
    
         
            +
                  user_cert.country
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                def common_name
         
     | 
| 
      
 135 
     | 
    
         
            +
                  user_cert.common_name
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                def organizational_unit
         
     | 
| 
      
 139 
     | 
    
         
            +
                  user_cert.organizational_unit
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                def serial_number
         
     | 
| 
      
 143 
     | 
    
         
            +
                  user_cert.serial_number
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
                alias personal_code serial_number
         
     | 
| 
      
 146 
     | 
    
         
            +
              end
         
     | 
| 
      
 147 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module MobileId
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Cert
         
     | 
| 
      
 5 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def root_path
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @root_path ||= File.expand_path('certs', __dir__)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def live_store
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @live_store ||= 
         
     | 
| 
      
 12 
     | 
    
         
            +
                      build_store([
         
     | 
| 
      
 13 
     | 
    
         
            +
                        File.join(root_path, 'EE_Certification_Centre_Root_CA.pem.crt'),
         
     | 
| 
      
 14 
     | 
    
         
            +
                        File.join(root_path, 'ESTEID-SK_2015.pem.crt')
         
     | 
| 
      
 15 
     | 
    
         
            +
                      ])
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def test_store
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @test_store ||= 
         
     | 
| 
      
 20 
     | 
    
         
            +
                      build_store([
         
     | 
| 
      
 21 
     | 
    
         
            +
                        File.join(root_path, 'TEST_of_EE_Certification_Centre_Root_CA.pem.crt'),
         
     | 
| 
      
 22 
     | 
    
         
            +
                        File.join(root_path, 'TEST_of_ESTEID-SK_2015.pem.crt')
         
     | 
| 
      
 23 
     | 
    
         
            +
                      ])
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def build_store(paths)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    store = OpenSSL::X509::Store.new
         
     | 
| 
      
 28 
     | 
    
         
            +
                    paths.each { |path| cert = OpenSSL::X509::Certificate.new(File.read(path)); store.add_cert(cert) }
         
     | 
| 
      
 29 
     | 
    
         
            +
                    store
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                attr_accessor :cert, :subject
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def initialize(base64_cert, live:)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  self.cert = OpenSSL::X509::Certificate.new(Base64.decode64(base64_cert))
         
     | 
| 
      
 37 
     | 
    
         
            +
                  verify!(self.cert, live: live)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  build_cert_subject
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def verify!(cert, live:)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  store = live == true ? self.class.live_store : self.class.test_store
         
     | 
| 
      
 43 
     | 
    
         
            +
                  raise Error, 'User certificate is not valid' unless store.verify(cert)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  raise Error, 'User certificate is not valid' unless cert.public_key.check_key
         
     | 
| 
      
 45 
     | 
    
         
            +
                  raise Error, 'User certificate is expired' unless (cert.not_before..cert.not_after) === Time.now
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  true
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def verify_signature!(signature, doc)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # TODO OpenSSL does not parse signature
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # cert.public_key.verify(OpenSSL::Digest::SHA256.new, signature, doc)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def given_name
         
     | 
| 
      
 56 
     | 
    
         
            +
                  subject["GN"].tr(",", " ")
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
                alias first_name given_name
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def surname
         
     | 
| 
      
 61 
     | 
    
         
            +
                  subject["SN"].tr(",", " ")
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
                alias last_name surname
         
     | 
| 
      
 64 
     | 
    
         
            +
                
         
     | 
| 
      
 65 
     | 
    
         
            +
                def country
         
     | 
| 
      
 66 
     | 
    
         
            +
                  subject["C"].tr(",", " ")
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                def common_name
         
     | 
| 
      
 70 
     | 
    
         
            +
                  subject["CN"]
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def organizational_unit
         
     | 
| 
      
 74 
     | 
    
         
            +
                  subject["OU"]
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def serial_number
         
     | 
| 
      
 78 
     | 
    
         
            +
                  subject["serialNumber"]
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
                alias personal_code serial_number
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                private
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def build_cert_subject
         
     | 
| 
      
 85 
     | 
    
         
            +
                  self.subject = cert.subject.to_utf8.split(/(?<!\\)\,+/).each_with_object({}) do |c, result|
         
     | 
| 
      
 86 
     | 
    
         
            +
                    next unless c.include?("=")
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    key, val = c.split("=")
         
     | 
| 
      
 89 
     | 
    
         
            +
                    result[key] = val
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----BEGIN CERTIFICATE-----
         
     | 
| 
      
 2 
     | 
    
         
            +
            MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1
         
     | 
| 
      
 3 
     | 
    
         
            +
            MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
         
     | 
| 
      
 4 
     | 
    
         
            +
            czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
         
     | 
| 
      
 5 
     | 
    
         
            +
            CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy
         
     | 
| 
      
 6 
     | 
    
         
            +
            MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl
         
     | 
| 
      
 7 
     | 
    
         
            +
            ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS
         
     | 
| 
      
 8 
     | 
    
         
            +
            b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB
         
     | 
| 
      
 9 
     | 
    
         
            +
            AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy
         
     | 
| 
      
 10 
     | 
    
         
            +
            euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO
         
     | 
| 
      
 11 
     | 
    
         
            +
            bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw
         
     | 
| 
      
 12 
     | 
    
         
            +
            WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d
         
     | 
| 
      
 13 
     | 
    
         
            +
            MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE
         
     | 
| 
      
 14 
     | 
    
         
            +
            1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD
         
     | 
| 
      
 15 
     | 
    
         
            +
            VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/
         
     | 
| 
      
 16 
     | 
    
         
            +
            zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB
         
     | 
| 
      
 17 
     | 
    
         
            +
            BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF
         
     | 
| 
      
 18 
     | 
    
         
            +
            BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV
         
     | 
| 
      
 19 
     | 
    
         
            +
            v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG
         
     | 
| 
      
 20 
     | 
    
         
            +
            E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
         
     | 
| 
      
 21 
     | 
    
         
            +
            uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW
         
     | 
| 
      
 22 
     | 
    
         
            +
            iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v
         
     | 
| 
      
 23 
     | 
    
         
            +
            GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=
         
     | 
| 
      
 24 
     | 
    
         
            +
            -----END CERTIFICATE-----
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----BEGIN CERTIFICATE-----
         
     | 
| 
      
 2 
     | 
    
         
            +
            MIIGcDCCBVigAwIBAgIQRUgJC4ec7yFWcqzT3mwbWzANBgkqhkiG9w0BAQwFADB1
         
     | 
| 
      
 3 
     | 
    
         
            +
            MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
         
     | 
| 
      
 4 
     | 
    
         
            +
            czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
         
     | 
| 
      
 5 
     | 
    
         
            +
            CSqGSIb3DQEJARYJcGtpQHNrLmVlMCAXDTE1MTIxNzEyMzg0M1oYDzIwMzAxMjE3
         
     | 
| 
      
 6 
     | 
    
         
            +
            MjM1OTU5WjBjMQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVy
         
     | 
| 
      
 7 
     | 
    
         
            +
            aW1pc2tlc2t1czEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxFzAVBgNVBAMMDkVT
         
     | 
| 
      
 8 
     | 
    
         
            +
            VEVJRC1TSyAyMDE1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0oH6
         
     | 
| 
      
 9 
     | 
    
         
            +
            1NDxbdW9k8nLA1qGaL4B7vydod2Ewp/STBZB3wEtIJCLdkpEsS8pXfFiRqwDVsgG
         
     | 
| 
      
 10 
     | 
    
         
            +
            Gbu+Q99trlb5LI7yi7rIkRov5NftBdSNPSU5rAhYPQhvZZQgOwRaHa5Ey+BaLJHm
         
     | 
| 
      
 11 
     | 
    
         
            +
            LqYQS9hQvQsCYyws+xVvNFUpK0pGD64iycqdMuBl/nWq3fLuZppwBh0VFltm4nhr
         
     | 
| 
      
 12 
     | 
    
         
            +
            /1S0R9TRJpqFUGbGr4OK/DwebQ5PjhdS40gCUNwmC7fPQ4vIH+x+TCk2aG+u3MoA
         
     | 
| 
      
 13 
     | 
    
         
            +
            z0IrpVWqiwzG/vxreuPPAkgXeFCeYf6fXLsGz4WivsZFbph2pMjELu6sltlBXfAG
         
     | 
| 
      
 14 
     | 
    
         
            +
            3fGv43t91VXicyzR/eT5dsB+zFsW1sHV+1ONPr+qzgDxCH2cmuqoZNfIIq+buob3
         
     | 
| 
      
 15 
     | 
    
         
            +
            eA8ee+XpJKJQr+1qGrmhggjvAhc7m6cU4x/QfxwRYhIVNhJf+sKVThkQhbJ9XxuK
         
     | 
| 
      
 16 
     | 
    
         
            +
            k3c18wymwL1mpDD0PIGJqlssMeiuJ4IzagFbgESGNDUd4icm0hQT8CmQeUm1GbWe
         
     | 
| 
      
 17 
     | 
    
         
            +
            BYseqPhMQX97QFBLXJLVy2SCyoAz7Bq1qA43++EcibN+yBc1nQs2Zoq8ck9MK0bC
         
     | 
| 
      
 18 
     | 
    
         
            +
            xDMeUkQUz6VeQGp69ImOQrsw46qTz0mtdQrMSbnkXCuLan5dPm284J9HmaqiYi6j
         
     | 
| 
      
 19 
     | 
    
         
            +
            6KLcZ2NkUnDQFesBVlMEm+fHa2iR6lnAFYZ06UECAwEAAaOCAgowggIGMB8GA1Ud
         
     | 
| 
      
 20 
     | 
    
         
            +
            IwQYMBaAFBLyWj7qVhy/zQas8fElyalL1BSZMB0GA1UdDgQWBBSzq4i8mdVipIUq
         
     | 
| 
      
 21 
     | 
    
         
            +
            CM20HXI7g3JHUTAOBgNVHQ8BAf8EBAMCAQYwdwYDVR0gBHAwbjAIBgYEAI96AQIw
         
     | 
| 
      
 22 
     | 
    
         
            +
            CQYHBACL7EABAjAwBgkrBgEEAc4fAQEwIzAhBggrBgEFBQcCARYVaHR0cHM6Ly93
         
     | 
| 
      
 23 
     | 
    
         
            +
            d3cuc2suZWUvQ1BTMAsGCSsGAQQBzh8BAjALBgkrBgEEAc4fAQMwCwYJKwYBBAHO
         
     | 
| 
      
 24 
     | 
    
         
            +
            HwEEMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYDVR0eBDowOKE2MASCAiIiMAqHCAAA
         
     | 
| 
      
 25 
     | 
    
         
            +
            AAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCcGA1Ud
         
     | 
| 
      
 26 
     | 
    
         
            +
            JQQgMB4GCCsGAQUFBwMJBggrBgEFBQcDAgYIKwYBBQUHAwQwfAYIKwYBBQUHAQEE
         
     | 
| 
      
 27 
     | 
    
         
            +
            cDBuMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcC5zay5lZS9DQTBKBggrBgEFBQcw
         
     | 
| 
      
 28 
     | 
    
         
            +
            AoY+aHR0cDovL3d3dy5zay5lZS9jZXJ0cy9FRV9DZXJ0aWZpY2F0aW9uX0NlbnRy
         
     | 
| 
      
 29 
     | 
    
         
            +
            ZV9Sb290X0NBLmRlci5jcnQwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL3d3dy5z
         
     | 
| 
      
 30 
     | 
    
         
            +
            ay5lZS9yZXBvc2l0b3J5L2NybHMvZWVjY3JjYS5jcmwwDQYJKoZIhvcNAQEMBQAD
         
     | 
| 
      
 31 
     | 
    
         
            +
            ggEBAHRWDGI3P00r2sOnlvLHKk9eE7X93eT+4e5TeaQsOpE5zQRUTtshxN8Bnx2T
         
     | 
| 
      
 32 
     | 
    
         
            +
            oQ9rgi18q+MwXm2f0mrGakYYG0bix7ZgDQvCMD/kuRYmwLGdfsTXwh8KuL6uSHF+
         
     | 
| 
      
 33 
     | 
    
         
            +
            U/ZTss6qG7mxCHG9YvebkN5Yj/rYRvZ9/uJ9rieByxw4wo7b19p22PXkAkXP5y3+
         
     | 
| 
      
 34 
     | 
    
         
            +
            qK/Oet98lqwI97kJhiS2zxFYRk+dXbazmoVHnozYKmsZaSUvoYNNH19tpS7BLdsg
         
     | 
| 
      
 35 
     | 
    
         
            +
            i9KpbvQLb5ywIMq9ut3+b2Xvzq8yzmHMFtLIJ6Afu1jJpqD82BUAFcvi5vhnP8M7
         
     | 
| 
      
 36 
     | 
    
         
            +
            b974R18WCOpgNQvXDI+2/8ZINeU=
         
     | 
| 
      
 37 
     | 
    
         
            +
            -----END CERTIFICATE-----
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----BEGIN CERTIFICATE-----
         
     | 
| 
      
 2 
     | 
    
         
            +
            MIIEEzCCAvugAwIBAgIQc/jtqiMEFERMtVvsSsH7sjANBgkqhkiG9w0BAQUFADB9
         
     | 
| 
      
 3 
     | 
    
         
            +
            MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
         
     | 
| 
      
 4 
     | 
    
         
            +
            czEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290
         
     | 
| 
      
 5 
     | 
    
         
            +
            IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwIhgPMjAxMDEwMDcxMjM0NTZa
         
     | 
| 
      
 6 
     | 
    
         
            +
            GA8yMDMwMTIxNzIzNTk1OVowfTELMAkGA1UEBhMCRUUxIjAgBgNVBAoMGUFTIFNl
         
     | 
| 
      
 7 
     | 
    
         
            +
            cnRpZml0c2VlcmltaXNrZXNrdXMxMDAuBgNVBAMMJ1RFU1Qgb2YgRUUgQ2VydGlm
         
     | 
| 
      
 8 
     | 
    
         
            +
            aWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVl
         
     | 
| 
      
 9 
     | 
    
         
            +
            MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1gGpqCtDmNNEHUjC8LXq
         
     | 
| 
      
 10 
     | 
    
         
            +
            xRdC1kpjDgkzOTxQynzDxw/xCjy5hhyG3xX4RPrW9Z6k5ZNTNS+xzrZgQ9m5U6uM
         
     | 
| 
      
 11 
     | 
    
         
            +
            ywYpx3F3DVgbdQLd8DsLmuVOz02k/TwoRt1uP6xtV9qG0HsGvN81q3HvPR/zKtA7
         
     | 
| 
      
 12 
     | 
    
         
            +
            MmNZuwuDFQwsguKgDR2Jfk44eKmLfyzvh+Xe6Cr5+zRnsVYwMA9bgBaOZMv1TwTT
         
     | 
| 
      
 13 
     | 
    
         
            +
            VNi9H1ltK32Z+IhUX8W5f2qVP33R1wWCKapK1qTX/baXFsBJj++F8I8R6+gSyC3D
         
     | 
| 
      
 14 
     | 
    
         
            +
            kV5N/pOlWPzZYx+kHRkRe/oddURA9InJwojbnsH+zJOa2VrNKakNv2HnuYCIonzu
         
     | 
| 
      
 15 
     | 
    
         
            +
            pwIDAQABo4GKMIGHMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
         
     | 
| 
      
 16 
     | 
    
         
            +
            A1UdDgQWBBS1NAqdpS8QxechDr7EsWVHGwN2/jBFBgNVHSUEPjA8BggrBgEFBQcD
         
     | 
| 
      
 17 
     | 
    
         
            +
            AgYIKwYBBQUHAwEGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUF
         
     | 
| 
      
 18 
     | 
    
         
            +
            BwMJMA0GCSqGSIb3DQEBBQUAA4IBAQAj72VtxIw6p5lqeNmWoQ48j8HnUBM+6mI0
         
     | 
| 
      
 19 
     | 
    
         
            +
            I+VkQr0EfQhfmQ5KFaZwnIqxWrEPaxRjYwV0xKa1AixVpFOb1j+XuVmgf7khxXTy
         
     | 
| 
      
 20 
     | 
    
         
            +
            Bmd8JRLwl7teCkD1SDnU/yHmwY7MV9FbFBd+5XK4teHVvEVRsJ1oFwgcxVhyoviR
         
     | 
| 
      
 21 
     | 
    
         
            +
            SnbIPaOvk+0nxKClrlS6NW5TWZ+yG55z8OCESHaL6JcimkLFjRjSsQDWIEtDvP4S
         
     | 
| 
      
 22 
     | 
    
         
            +
            tH3vIMUPPiKdiNkGjVLSdChwkW3z+m0EvAjyD9rnGCmjeEm5diLFu7VMNVqupsbZ
         
     | 
| 
      
 23 
     | 
    
         
            +
            SfDzzBLc5+6TqgQTOG7GaZk2diMkn03iLdHGFrh8ML+mXG9SjEPI
         
     | 
| 
      
 24 
     | 
    
         
            +
            -----END CERTIFICATE-----
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----BEGIN CERTIFICATE-----
         
     | 
| 
      
 2 
     | 
    
         
            +
            MIIGgzCCBWugAwIBAgIQEDb9gCZi4PdWc7IoNVIbsTANBgkqhkiG9w0BAQwFADB9
         
     | 
| 
      
 3 
     | 
    
         
            +
            MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
         
     | 
| 
      
 4 
     | 
    
         
            +
            czEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290
         
     | 
| 
      
 5 
     | 
    
         
            +
            IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwIBcNMTUxMjE4MDcxMzQ0WhgP
         
     | 
| 
      
 6 
     | 
    
         
            +
            MjAzMDEyMTcyMzU5NTlaMGsxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0
         
     | 
| 
      
 7 
     | 
    
         
            +
            aWZpdHNlZXJpbWlza2Vza3VzMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEfMB0G
         
     | 
| 
      
 8 
     | 
    
         
            +
            A1UEAwwWVEVTVCBvZiBFU1RFSUQtU0sgMjAxNTCCAiIwDQYJKoZIhvcNAQEBBQAD
         
     | 
| 
      
 9 
     | 
    
         
            +
            ggIPADCCAgoCggIBAMTeAFvLxmAeaOsRKaf+hlkOhW+CdEilmUIKWs+qCWVq+w8E
         
     | 
| 
      
 10 
     | 
    
         
            +
            8PA/TohAZdUcO4KFXothmPDmfOCb0ExXcnOPCr2NndavzB39htlyYKYxkOkZi3pL
         
     | 
| 
      
 11 
     | 
    
         
            +
            z8bZg/HvpBoy8KIg0sYdbhVPYHf6i7fuJjDac4zN1vKdVQXA6Tv5wS/e90/ZyF95
         
     | 
| 
      
 12 
     | 
    
         
            +
            5vycxdNLticdozm5yCDMNgsEji6QNA1zIi3+C2YmnDXx6VyxhuC2R3q0xNkwtJ4e
         
     | 
| 
      
 13 
     | 
    
         
            +
            zs1RZGxWokTNPzQc3ilGhEJlVsS8vP624hUHwufQnwrKWpc3+D+plMIO0j3E+hmh
         
     | 
| 
      
 14 
     | 
    
         
            +
            46gIadDRweFR/dzb+CIBHRaFh0LEBjd/cDFQlBI+E8vpkhqeWp6rp1xwnhCL201M
         
     | 
| 
      
 15 
     | 
    
         
            +
            3E1E1Mw+51Xqj7WOfY0TzjOmQJy8WJPEwU2m44KxW1SnpeEBVkgb4XYFeQHAllc7
         
     | 
| 
      
 16 
     | 
    
         
            +
            J7JDv50BoIPpecgaqn1vKR7l//wDsL0MN1tDlBhl3x7TJ/fwMnwB1E3zVZR74TUZ
         
     | 
| 
      
 17 
     | 
    
         
            +
            h5J49CAcFrfM4RmP/0hcDW8+4wNWMg2Qgst2qmPZmHCI/OJt5yMt0Ud5yPF8AWxV
         
     | 
| 
      
 18 
     | 
    
         
            +
            ot3TxOBGjMiM8m6WsksFsQxp5WtA0DANGXIIfydTaTV16Mg+KpYVqFKxkvFBmfVp
         
     | 
| 
      
 19 
     | 
    
         
            +
            6xApMaFl3dY/m56O9JHEqFpBDF+uDQIMjFJxJ4Pt7Mdk40zfL4PSw9Qco2T3AgMB
         
     | 
| 
      
 20 
     | 
    
         
            +
            AAGjggINMIICCTAfBgNVHSMEGDAWgBS1NAqdpS8QxechDr7EsWVHGwN2/jAdBgNV
         
     | 
| 
      
 21 
     | 
    
         
            +
            HQ4EFgQUScDyRDll1ZtGOw04YIOx1i0ohqYwDgYDVR0PAQH/BAQDAgEGMGYGA1Ud
         
     | 
| 
      
 22 
     | 
    
         
            +
            IARfMF0wMQYKKwYBBAHOHwMBATAjMCEGCCsGAQUFBwIBFhVodHRwczovL3d3dy5z
         
     | 
| 
      
 23 
     | 
    
         
            +
            ay5lZS9DUFMwDAYKKwYBBAHOHwMBAjAMBgorBgEEAc4fAwEDMAwGCisGAQQBzh8D
         
     | 
| 
      
 24 
     | 
    
         
            +
            AQQwEgYDVR0TAQH/BAgwBgEB/wIBADBBBgNVHR4EOjA4oTYwBIICIiIwCocIAAAA
         
     | 
| 
      
 25 
     | 
    
         
            +
            AAAAAAAwIocgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwJwYDVR0l
         
     | 
| 
      
 26 
     | 
    
         
            +
            BCAwHgYIKwYBBQUHAwkGCCsGAQUFBwMCBggrBgEFBQcDBDCBiQYIKwYBBQUHAQEE
         
     | 
| 
      
 27 
     | 
    
         
            +
            fTB7MCUGCCsGAQUFBzABhhlodHRwOi8vZGVtby5zay5lZS9jYV9vY3NwMFIGCCsG
         
     | 
| 
      
 28 
     | 
    
         
            +
            AQUFBzAChkZodHRwOi8vd3d3LnNrLmVlL2NlcnRzL1RFU1Rfb2ZfRUVfQ2VydGlm
         
     | 
| 
      
 29 
     | 
    
         
            +
            aWNhdGlvbl9DZW50cmVfUm9vdF9DQS5kZXIuY3J0MEMGA1UdHwQ8MDowOKA2oDSG
         
     | 
| 
      
 30 
     | 
    
         
            +
            Mmh0dHBzOi8vd3d3LnNrLmVlL3JlcG9zaXRvcnkvY3Jscy90ZXN0X2VlY2NyY2Eu
         
     | 
| 
      
 31 
     | 
    
         
            +
            Y3JsMA0GCSqGSIb3DQEBDAUAA4IBAQDBOYTpbbQuoJKAmtDPpAomDd9mKZCarIPx
         
     | 
| 
      
 32 
     | 
    
         
            +
            AH8UXphSndMqOmIUA4oQMrLcZ6a0rMyCFR8x4NX7abc8T81cvgUAWjfNFn8+bi6+
         
     | 
| 
      
 33 
     | 
    
         
            +
            DgbjhYY+wZ010MHHdUo2xPajfog8cDWJPkmz+9PAdyjzhb1eYoEnm5D6o4hZQCiR
         
     | 
| 
      
 34 
     | 
    
         
            +
            yPnOKp7LZcpsVz1IFXsqP7M5WgHk0SqY1vs+Yhu7zWPSNYFIzNNXGoUtfKhhkHiR
         
     | 
| 
      
 35 
     | 
    
         
            +
            WFX/wdzr3fqeaQ3gs/PyD53YuJXRzFrktgJJoJWnHEYIhEwbai9+OeKr4L4kTkxv
         
     | 
| 
      
 36 
     | 
    
         
            +
            PKTyjjpLKcjUk0Y0cxg7BuzwevonyBtL72b/FVs6XsXJJqCa3W4T
         
     | 
| 
      
 37 
     | 
    
         
            +
            -----END CERTIFICATE-----
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            en:
         
     | 
| 
      
 2 
     | 
    
         
            +
              mobile_id:
         
     | 
| 
      
 3 
     | 
    
         
            +
                some_error: There was some error
         
     | 
| 
      
 4 
     | 
    
         
            +
                timeout: "Mobile-ID session got timeout"
         
     | 
| 
      
 5 
     | 
    
         
            +
                user_is_not_mobile_id_client: User is not Mobile-ID client.
         
     | 
| 
      
 6 
     | 
    
         
            +
                user_cancelled: User cancelled the Mobile ID operation
         
     | 
| 
      
 7 
     | 
    
         
            +
                signature_hash_mismatch: "Mobile-ID has signiture issue. User needs to contact his/her mobile operator."
         
     | 
| 
      
 8 
     | 
    
         
            +
                phone_absent: Mobile-ID SIM not available
         
     | 
| 
      
 9 
     | 
    
         
            +
                delivery_error: Mobile-ID SMS sending error.
         
     | 
| 
      
 10 
     | 
    
         
            +
                sim_error: Invalid response from Mobile-ID SIM card
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            et:
         
     | 
| 
      
 2 
     | 
    
         
            +
              mobile_id:
         
     | 
| 
      
 3 
     | 
    
         
            +
                some_error: Tekkis viga
         
     | 
| 
      
 4 
     | 
    
         
            +
                timeout: "Mobiil-ID sisselogimine aegus"
         
     | 
| 
      
 5 
     | 
    
         
            +
                user_is_not_mobile_id_client: Kasutaja ei ole Mobiil-ID klient
         
     | 
| 
      
 6 
     | 
    
         
            +
                user_cancelled: Kasutaja katkestas Mobiil-ID sisselogimise.
         
     | 
| 
      
 7 
     | 
    
         
            +
                signature_hash_mismatch: "Mobiil-ID digiallkiri on vigane. Palun pöörduge oma mobiilioperaatori poole."
         
     | 
| 
      
 8 
     | 
    
         
            +
                phone_absent: Kasutaja telefon ei asu levipiirkonnas või on välja lülitatud.
         
     | 
| 
      
 9 
     | 
    
         
            +
                delivery_error: Mobiil-ID SMS saatmisel tekkis viga.
         
     | 
| 
      
 10 
     | 
    
         
            +
                sim_error: Mobiil-ID telefoni SIM viga.
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ru:
         
     | 
| 
      
 2 
     | 
    
         
            +
              mobile_id:
         
     | 
| 
      
 3 
     | 
    
         
            +
                some_error: Была некоторая ошибка
         
     | 
| 
      
 4 
     | 
    
         
            +
                timeout: "Mobile-ID session got timeout"
         
     | 
| 
      
 5 
     | 
    
         
            +
                user_is_not_mobile_id_client: User is not Mobile-ID client.
         
     | 
| 
      
 6 
     | 
    
         
            +
                user_cancelled: User cancelled the Mobile ID operation
         
     | 
| 
      
 7 
     | 
    
         
            +
                signature_hash_mismatch: "Mobile-ID has signiture issue. User needs to contact his/her mobile operator."
         
     | 
| 
      
 8 
     | 
    
         
            +
                phone_absent: Mobile-ID SIM not available
         
     | 
| 
      
 9 
     | 
    
         
            +
                delivery_error: Mobile-ID SMS sending error.
         
     | 
| 
      
 10 
     | 
    
         
            +
                sim_error: Invalid response from Mobile-ID SIM card
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rails'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module MobileId
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Railtie < ::Rails::Railtie #:nodoc:
         
     | 
| 
      
 5 
     | 
    
         
            +
                initializer 'mobile_id' do |app|
         
     | 
| 
      
 6 
     | 
    
         
            +
                  DeviseI18n::Railtie.instance_eval do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    (app.config.i18n.available_locales & MobileId::LOCALES).each do |loc|
         
     | 
| 
      
 8 
     | 
    
         
            +
                      I18n.load_path << File.expand_path("locales/#{loc}.yml", __dir__)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    end
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: mobile_id
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.7
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Priit Tark
         
     | 
| 
         @@ -100,7 +100,20 @@ executables: [] 
     | 
|
| 
       100 
100 
     | 
    
         
             
            extensions: []
         
     | 
| 
       101 
101 
     | 
    
         
             
            extra_rdoc_files: []
         
     | 
| 
       102 
102 
     | 
    
         
             
            files:
         
     | 
| 
      
 103 
     | 
    
         
            +
            - CHANGELOG.md
         
     | 
| 
      
 104 
     | 
    
         
            +
            - MIT-LICENSE
         
     | 
| 
      
 105 
     | 
    
         
            +
            - README.md
         
     | 
| 
       103 
106 
     | 
    
         
             
            - lib/mobile_id.rb
         
     | 
| 
      
 107 
     | 
    
         
            +
            - lib/mobile_id/auth.rb
         
     | 
| 
      
 108 
     | 
    
         
            +
            - lib/mobile_id/cert.rb
         
     | 
| 
      
 109 
     | 
    
         
            +
            - lib/mobile_id/certs/EE_Certification_Centre_Root_CA.pem.crt
         
     | 
| 
      
 110 
     | 
    
         
            +
            - lib/mobile_id/certs/ESTEID-SK_2015.pem.crt
         
     | 
| 
      
 111 
     | 
    
         
            +
            - lib/mobile_id/certs/TEST_of_EE_Certification_Centre_Root_CA.pem.crt
         
     | 
| 
      
 112 
     | 
    
         
            +
            - lib/mobile_id/certs/TEST_of_ESTEID-SK_2015.pem.crt
         
     | 
| 
      
 113 
     | 
    
         
            +
            - lib/mobile_id/locales/en.yml
         
     | 
| 
      
 114 
     | 
    
         
            +
            - lib/mobile_id/locales/et.yml
         
     | 
| 
      
 115 
     | 
    
         
            +
            - lib/mobile_id/locales/ru.yml
         
     | 
| 
      
 116 
     | 
    
         
            +
            - lib/mobile_id/railtie.rb
         
     | 
| 
       104 
117 
     | 
    
         
             
            homepage: https://github.com/gitlabeu/mobile_id
         
     | 
| 
       105 
118 
     | 
    
         
             
            licenses:
         
     | 
| 
       106 
119 
     | 
    
         
             
            - MIT
         
     |