mobile_id 0.0.1

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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/mobile_id.rb +161 -0
  3. metadata +127 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4fe6d1fd810346d147526247e6caff4a425668840b1926efaae177151ffac96d
4
+ data.tar.gz: d3030278e561fa6959e92cf1fb4b928d3381a4a604e79e5e4b3ac0d95ed98525
5
+ SHA512:
6
+ metadata.gz: 1ab4acaef19ceaea34fd9c28e55984a9b07bc220304dc1b92ba8c7f647a73f283256f0d4c7a30128ba1894fd56d8ed435a1c22cd92022a3add06995ac243be82
7
+ data.tar.gz: 60acfeb6677a3da2534ec390b2b991b1826ce0780c3d6334774619a2dd3b63b441eeed436d465f558b2f064151953a707ec0ec26a7285572d05fb0293029db55
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'digest'
5
+ require 'httparty'
6
+ require 'active_support/core_ext/hash/indifferent_access'
7
+ require 'i18n'
8
+ if defined?(Rails)
9
+ require 'mobile_id/railtie'
10
+ else
11
+ I18n.load_path << Dir[File.expand_path("lib/mobile_id/locales") + "/*.yml"]
12
+ end
13
+
14
+ class MobileId
15
+ class Error < StandardError; end
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
161
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mobile_id
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Priit Tark
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: openssl
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: i18n
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Estonia Mobile ID authentication, more info at https://www.id.ee/en/
98
+ email: priit@gitlab.eu
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - lib/mobile_id.rb
104
+ homepage: https://github.com/gitlabeu/mobile_id
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubygems_version: 3.1.4
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Estonia Mobile ID authentication
127
+ test_files: []