mobile_id 0.0.3 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d38624f18a2ecc7fc1118e8f4cbe3d02276d13a1e04a2cd224c65b63eecab66
4
- data.tar.gz: 3fe078951586eca758a792918c705306f2a2058f2f63385cfe4eb18cd1455a16
3
+ metadata.gz: 99c9c1d9c44d00d271fa3b42aba146322950aa8bec19a149557530cbe4fc2cf8
4
+ data.tar.gz: 4502fa084cad790ee395600599e3babb4ae1e10d538141106bb049c855f2be6e
5
5
  SHA512:
6
- metadata.gz: 68b5151f552cdc6ef5730ef3a9ed21cffed2cf18a839deb32f91039cbbabf73b47bd0aad4f2046f57b9452c395b41f23c525d35aa6935adca7f80139a32ff805
7
- data.tar.gz: 8eff21fe89c9a3f6c3328e326cae799ad4c727d3545255d41c643a53702058b544ba811e2083635ba303077e57bbc7c493f1fdf1e94ba9b6dcfdf39b83fffc3c
6
+ metadata.gz: a032c0f18198697d25f81aec5adbddff64ecd72f4b010dabae52556ae23a379d4f35b2a469851dc1e10a9f798b378e4cd2f3e662cac7a0d3017ad68314c9403c
7
+ data.tar.gz: 34ec448de3a9f6c9f620ba10de1f88be4f012b4878ae55fac6f9dd74023f4d9615cd083f117bd40db860673167fda83869c3bacfb0ba95656fecca0b4d48282c
@@ -1,3 +1,18 @@
1
+ Release 0.0.7
2
+ * Release cleanup
3
+ *
4
+ Release 0.0.7
5
+ * Cert cleanup
6
+
7
+ Release 0.0.6
8
+ * Cert path fix
9
+
10
+ Release 0.0.5
11
+ * Added user certificate validation
12
+
13
+ Release 0.0.4
14
+ * Refactored MobileId to MobileId::Auth
15
+
1
16
  Release 0.0.3
2
17
  * Gemspec update
3
18
 
data/README.md CHANGED
@@ -25,8 +25,8 @@ Execute irb:
25
25
  $ bundle exec irb
26
26
  irb(main):001:0> require 'mobile_id'
27
27
  => true
28
- irb(main):002:0> @mid = MobileId.new(live: false)
29
- => #<MobileId:0x000055ac4cb25630 @url="https://tsp.demo.sk.ee/mid-api", @uuid="00000000-0000-0000-0000-000000000000", @name="DEMO", @hash="two+e7UMoFCAXHo8q9AnWqSC58Hhil74RowY8Gg9xQY=">
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
30
  irb(main):003:0> auth = @mid.authenticate!(phone: '00000766', personal_code: '60001019906')
31
31
  => {"session_id"=>"34e7eff0-691b-4fad-9798-8db680587b18", "phone"=>"00000766", "phone_calling_code"=>"+372"}
32
32
  irb(main):004:0> verify = @mid.verify!(auth)
@@ -40,7 +40,7 @@ You get verified attributes: personal_code, first_name, last_name, phone, phone_
40
40
  For live usage, add your relyingPartyUUID (RPUUID) and relyingPartyName what you get from https://www.sk.ee
41
41
 
42
42
  ```ruby
43
- @mid = MobileId.new(live: true, uuid: "39e7eff0-241b-4fad-2798-9db680587b20", name: 'My service name')
43
+ @mid = MobileId::Auth.new(live: true, uuid: "39e7eff0-241b-4fad-2798-9db680587b20", name: 'My service name')
44
44
  ```
45
45
 
46
46
  Rails with Devise example controller:
@@ -109,12 +109,18 @@ end
109
109
 
110
110
  After checking out the repo, run `bundle` to install dependencies. For testing code, run `rspec`
111
111
 
112
+ ## Contributors
113
+
114
+ * Priit Tark
115
+ * Andri Möll for pointing out user signature issue
116
+
112
117
  ## Contributing
113
118
 
114
119
  Bug reports and pull requests are welcome on GitHub at https://github.com/gitlabeu/mobile_id
115
120
 
116
121
  ## Roadmap
117
122
 
123
+ * Auth signature validation
118
124
  * Document sign
119
125
  * Rails generators
120
126
 
@@ -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
- class MobileId
14
+ module MobileId
15
15
  class Error < StandardError; end
16
16
 
17
- # API documentation https://github.com/SK-EID/MID
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-----
@@ -4,8 +4,8 @@ module MobileId
4
4
  class Railtie < ::Rails::Railtie #:nodoc:
5
5
  initializer 'mobile_id' do |app|
6
6
  DeviseI18n::Railtie.instance_eval do
7
- app.config.i18n.available_locales.each do |loc|
8
- I18n.load_path << Dir[File.expand_path("lib/mobile_id/locales") + "/#{loc}.yml"]
7
+ (app.config.i18n.available_locales & MobileId::LOCALES).each do |loc|
8
+ I18n.load_path << File.expand_path("locales/#{loc}.yml", __dir__)
9
9
  end
10
10
  end
11
11
  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.3
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Priit Tark
@@ -104,6 +104,12 @@ files:
104
104
  - MIT-LICENSE
105
105
  - README.md
106
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
107
113
  - lib/mobile_id/locales/en.yml
108
114
  - lib/mobile_id/locales/et.yml
109
115
  - lib/mobile_id/locales/ru.yml