mobile_id 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d38624f18a2ecc7fc1118e8f4cbe3d02276d13a1e04a2cd224c65b63eecab66
4
- data.tar.gz: 3fe078951586eca758a792918c705306f2a2058f2f63385cfe4eb18cd1455a16
3
+ metadata.gz: ac2213a077be1331007897be4a68ddde6e428cb7b4a0ca712950367d38c5d6c7
4
+ data.tar.gz: 7d7736fb27da9413c707b30ea98797a5dcbe05160ff2fc434b802fdf58310645
5
5
  SHA512:
6
- metadata.gz: 68b5151f552cdc6ef5730ef3a9ed21cffed2cf18a839deb32f91039cbbabf73b47bd0aad4f2046f57b9452c395b41f23c525d35aa6935adca7f80139a32ff805
7
- data.tar.gz: 8eff21fe89c9a3f6c3328e326cae799ad4c727d3545255d41c643a53702058b544ba811e2083635ba303077e57bbc7c493f1fdf1e94ba9b6dcfdf39b83fffc3c
6
+ metadata.gz: 3e04950d1fda22037f6e7f5f72bbf1b0f4038632028940e80bb020626efa54b46d94bd1af4f01c99113db5cf6f58fa6f6e2a6578543ef6b85771e6a88ef86487
7
+ data.tar.gz: bee3d0498d13db91e956c8daf69df2bd4e3c659be5379e40b1a6a9e1d3e7ddbd5f58c310f01c1bd9ed16f6ee92ee4ed6ea027627f770a7915fedda5a3e198382
@@ -1,3 +1,6 @@
1
+ Release 0.0.4
2
+ * Refactored MobileId to MobileId::Auth
3
+
1
4
  Release 0.0.3
2
5
  * Gemspec update
3
6
 
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:
@@ -11,151 +11,10 @@ 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/auth'
@@ -0,0 +1,150 @@
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, :hash, :cert, :cert_subject
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.hash = Digest::SHA256.base64digest(SecureRandom.uuid)
19
+ end
20
+
21
+ def authenticate!(phone_calling_code: nil, phone:, personal_code:, language: nil, display_text: nil)
22
+ phone_calling_code ||= '+372'
23
+ full_phone = "#{phone_calling_code}#{phone}"
24
+ language ||=
25
+ case I18n.locale
26
+ when :et
27
+ display_text ||= 'Autentimine'
28
+ 'EST'
29
+ when :ru
30
+ display_text ||= 'Аутентификация'
31
+ 'RUS'
32
+ else
33
+ display_text ||= 'Authentication'
34
+ 'ENG'
35
+ end
36
+
37
+ options = {
38
+ headers: {
39
+ "Content-Type": "application/json"
40
+ },
41
+ query: {},
42
+ body: {
43
+ relyingPartyUUID: uuid,
44
+ relyingPartyName: name,
45
+ phoneNumber: full_phone.to_s.strip,
46
+ nationalIdentityNumber: personal_code.to_s.strip,
47
+ hash: hash,
48
+ hashType: 'SHA256',
49
+ language: language,
50
+ displayText: display_text,
51
+ displayTextFormat: 'GSM-7' # or "UCS-2”
52
+ }.to_json
53
+ }
54
+
55
+ response = HTTParty.post(url + '/authentication', options)
56
+ raise Error, "#{I18n.t('mobile_id.some_error')} #{response}" unless response.code == 200
57
+
58
+ ActiveSupport::HashWithIndifferentAccess.new(
59
+ session_id: response['sessionID'],
60
+ phone: phone,
61
+ phone_calling_code: phone_calling_code
62
+ )
63
+ end
64
+
65
+ def verify!(auth)
66
+ long_poll!(session_id: auth['session_id'])
67
+
68
+ ActiveSupport::HashWithIndifferentAccess.new(
69
+ personal_code: personal_code,
70
+ first_name: first_name,
71
+ last_name: last_name,
72
+ phone: auth['phone'],
73
+ phone_calling_code: auth['phone_calling_code'],
74
+ auth_provider: 'mobileid' # User::MOBILEID
75
+ )
76
+ end
77
+
78
+ def long_poll!(session_id:)
79
+ response = HTTParty.get(url + "/authentication/session/#{session_id}")
80
+ raise Error, "#{I18n.t('mobile_id.some_error')} #{response.code} #{response}" if response.code != 200
81
+
82
+ if response['state'] == 'COMPLETE' && response['result'] != 'OK'
83
+ message =
84
+ case response['result']
85
+ when "TIMEOUT"
86
+ I18n.t('mobile_id.timeout')
87
+ when "NOT_MID_CLIENT"
88
+ I18n.t('mobile_id.user_is_not_mobile_id_client')
89
+ when "USER_CANCELLED"
90
+ I18n.t('mobile_id.user_cancelled')
91
+ when "SIGNATURE_HASH_MISMATCH"
92
+ I18n.t('mobile_id.signature_hash_mismatch')
93
+ when "PHONE_ABSENT"
94
+ I18n.t('mobile_id.phone_absent')
95
+ when "DELIVERY_ERROR"
96
+ I18n.t('mobile_id.delivery_error')
97
+ when "SIM_ERROR"
98
+ I18n.t('mobile_id.sim_error')
99
+ end
100
+ raise Error, message
101
+ end
102
+
103
+ self.cert = OpenSSL::X509::Certificate.new(Base64.decode64(response['cert']))
104
+ self.cert_subject = build_cert_subject
105
+ cert
106
+ end
107
+
108
+ def verification_code
109
+ format("%04d", (Digest::SHA2.new(256).digest(Base64.decode64(hash))[-2..-1].unpack1('n') % 10000))
110
+ end
111
+
112
+ def given_name
113
+ cert_subject["GN"].tr(",", " ")
114
+ end
115
+ alias first_name given_name
116
+
117
+ def surname
118
+ cert_subject["SN"].tr(",", " ")
119
+ end
120
+ alias last_name surname
121
+
122
+ def country
123
+ cert_subject["C"].tr(",", " ")
124
+ end
125
+
126
+ def common_name
127
+ cert_subject["CN"]
128
+ end
129
+
130
+ def organizational_unit
131
+ cert_subject["OU"]
132
+ end
133
+
134
+ def serial_number
135
+ cert_subject["serialNumber"]
136
+ end
137
+ alias personal_code serial_number
138
+
139
+ private
140
+
141
+ def build_cert_subject
142
+ self.cert_subject = cert.subject.to_utf8.split(/(?<!\\)\,+/).each_with_object({}) do |c, result|
143
+ next unless c.include?("=")
144
+
145
+ key, val = c.split("=")
146
+ result[key] = val
147
+ end
148
+ end
149
+ end
150
+ end
@@ -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.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Priit Tark
@@ -104,6 +104,7 @@ files:
104
104
  - MIT-LICENSE
105
105
  - README.md
106
106
  - lib/mobile_id.rb
107
+ - lib/mobile_id/auth.rb
107
108
  - lib/mobile_id/locales/en.yml
108
109
  - lib/mobile_id/locales/et.yml
109
110
  - lib/mobile_id/locales/ru.yml