simplicity_client 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/simplicity_client.rb +147 -33
  3. metadata +25 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 495342a938dfee303d9653d8ea49bd7a8f94f9f31eaf367ac32de7ef1048b775
4
- data.tar.gz: ad30760937ee2466ed5b53026f7f64c5f36f8685141700dd236e1645275c81a9
3
+ metadata.gz: 35ccb4c05970e3765687119f1761b0c1ff47965ab6311f5e86e5fb321b8e87fd
4
+ data.tar.gz: dfc4d51cf8d179a2901c62aaa576828193ddf6ef87a9aba6793da75da6825737
5
5
  SHA512:
6
- metadata.gz: f2817cbe355a5c5c614ad16a644d27c9b12694e69644029db52e06ee2039fff3a173b3089a4d6bea406dd545adc2ad2ec0313c069c8b0892efc50a67b1723148
7
- data.tar.gz: 58bc2f845410fd0687afc51135c28b20e42a1dcdd1bacf89e8b240358d5b8a610ee0c5c3c77c7a4839c89130c6f51cef763195ed8bda0730f7a06007acf28f3e
6
+ metadata.gz: 6ef0ea4b00d2ae9ae5deaaf317759fe595e7221fbfe46175c48747355e388ab4faaf4f0b272ccd6c57ec7c11fc7f06037dd35b6f9e76998c8258d36a6c406dfb
7
+ data.tar.gz: 6c7618d98c48fc47adfa19931cb68a1fe67d612cc17e1e51c0a6cfdd7d708cffedf7dffd3ff96e425a890990c2b56d629541184edb033de49e2634d49f1e5be4
@@ -9,29 +9,45 @@ require "faraday"
9
9
  require "faraday-cookie_jar"
10
10
  require "faraday/follow_redirects"
11
11
  require "aws-sdk-cognitoidentityprovider"
12
- require "aws-cognito-srp"
13
12
  require "aws-sdk-cognitoidentity"
14
13
  require "aws-sigv4"
14
+ require_relative "fido2_client"
15
15
 
16
16
  module SimplicityClient
17
+ Params = Struct.new(:email, :credentialId, :keyAlgorithm, :keyCurve, :keyValue, :userHandle, keyword_init: true)
18
+ ParamDefinition = Struct.new(:name, :label, :primary_id)
19
+
17
20
  class Error < StandardError; end
18
21
 
22
+ # For the user interface
23
+ PARAMS_INFO = [
24
+ ParamDefinition.new(name: "email", label: "Email address", primary_id: true),
25
+ ParamDefinition.new(name: "credentialId", label: "Passkey credential ID"),
26
+ ParamDefinition.new(name: "keyAlgorithm", label: "Passkey key algorithm"),
27
+ ParamDefinition.new(name: "keyCurve", label: "Passkey key curve"),
28
+ ParamDefinition.new(name: "keyValue", label: "Passkey value"),
29
+ ParamDefinition.new(name: "userHandle", label: "Passkey user handle")
30
+ ].freeze
31
+
19
32
  class Session
20
33
  def initialize
21
34
  @logger = Logger.new $stderr
22
- @logger.level = Logger::INFO
35
+ @logger.level = Logger::DEBUG
23
36
 
24
37
  @user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
25
38
 
26
39
  @client = Faraday.new(
27
40
  headers: { "User-Agent" => @user_agent },
28
- # proxy: "http://Thinkbook.local:8080",
29
- # :ssl => {:verify => false}
30
- ) do |builder|
41
+ # proxy: "http://Thinkbook.local:8080",
42
+ # :ssl => {:verify => false}
43
+ ) do |builder|
31
44
  builder.response :follow_redirects
32
- # builder.response :logger
45
+ builder.response :logger
33
46
  builder.adapter Faraday.default_adapter
34
47
  end
48
+
49
+ @authsignal_base = "https://au.api.authsignal.com/v1"
50
+ @authsignal_tenant_id = "e768822f-b1a1-404c-a685-0e37905ca5f5"
35
51
  end
36
52
 
37
53
  # Write the session data out to a string so that the session can be restored later
@@ -47,49 +63,76 @@ module SimplicityClient
47
63
  @auth_data = json["auth_data"]
48
64
  end
49
65
 
50
- def login(username, password)
51
- client = Aws::CognitoIdentityProvider::Client.new(region: 'ap-southeast-2')
66
+ def login(params)
67
+ client = Aws::CognitoIdentityProvider::Client.new(region: "ap-southeast-2")
52
68
 
53
69
  user_pool_id = "ap-southeast-2_abAklW6ap"
54
70
 
55
- aws_srp = Aws::CognitoSrp.new(
56
- username: username.downcase,
57
- password: password,
58
- pool_id: user_pool_id,
59
- client_id: "kvoiu7unft0c8hqqsa6hkmeu5",
60
- aws_client: client,
71
+ device_id = SecureRandom.uuid
72
+ passkey = Fido2Client::Passkey.new(params.credentialId, params.keyAlgorithm, params.keyCurve, params.keyValue, params.userHandle)
73
+ challenge_id = fetch_challenge_id
74
+ authentication_options = fetch_authentication_options(challenge_id)
75
+ challenge = authentication_options["options"]["challenge"]
76
+ assertion = Fido2Client::Client.new.get_assertion(passkey, challenge)
77
+ passkey_result = present_passkey(challenge_id, assertion, device_id)
78
+
79
+ resp = client.initiate_auth(
80
+ {
81
+ auth_flow: "CUSTOM_AUTH",
82
+ auth_parameters: {
83
+ USERNAME: params.email,
84
+ },
85
+ client_metadata: {
86
+ anonymousId: device_id,
87
+ },
88
+ client_id: "kvoiu7unft0c8hqqsa6hkmeu5",
89
+ },
61
90
  )
62
91
 
63
- resp = aws_srp.authenticate
92
+ resp = client.respond_to_auth_challenge(
93
+ {
94
+ challenge_name: "CUSTOM_CHALLENGE",
95
+ challenge_responses: {
96
+ USERNAME: params.email,
97
+ ANSWER: passkey_result["accessToken"],
98
+ },
99
+ client_id: "kvoiu7unft0c8hqqsa6hkmeu5",
100
+ session: resp.session,
101
+ },
102
+ )
64
103
 
65
- cognito_identity_client = Aws::CognitoIdentity::Client.new(region: 'ap-southeast-2')
104
+ cognito_identity_client = Aws::CognitoIdentity::Client.new(region: "ap-southeast-2")
66
105
 
67
106
  # Assuming you have the Identity Pool ID and the ID token
68
- identity_pool_id = 'ap-southeast-2:0ed33fc6-4cef-4f2e-b634-31c616e108e2'
69
- id_token = resp.id_token
107
+ identity_pool_id = "ap-southeast-2:0ed33fc6-4cef-4f2e-b634-31c616e108e2"
108
+ id_token = resp.authentication_result.id_token
70
109
 
71
110
  # Get ID from the identity pool
72
- id_response = cognito_identity_client.get_id({
73
- identity_pool_id: identity_pool_id,
74
- logins: {
75
- "cognito-idp.ap-southeast-2.amazonaws.com/#{user_pool_id}" => id_token
76
- }
77
- })
111
+ id_response = cognito_identity_client.get_id(
112
+ {
113
+ identity_pool_id: identity_pool_id,
114
+ logins: {
115
+ "cognito-idp.ap-southeast-2.amazonaws.com/#{user_pool_id}" => id_token,
116
+ },
117
+ },
118
+ )
78
119
 
79
120
  # Get credentials for the ID
80
- credentials_response = cognito_identity_client.get_credentials_for_identity({
81
- identity_id: id_response.identity_id,
82
- logins: {
83
- "cognito-idp.ap-southeast-2.amazonaws.com/#{user_pool_id}" => id_token
84
- }
85
- })
121
+ credentials_response = cognito_identity_client.get_credentials_for_identity(
122
+ {
123
+ identity_id: id_response.identity_id,
124
+ logins: {
125
+ "cognito-idp.ap-southeast-2.amazonaws.com/#{user_pool_id}" => id_token,
126
+ },
127
+ },
128
+ )
86
129
 
87
130
  access_key_id = credentials_response.credentials.access_key_id
88
131
  secret_key = credentials_response.credentials.secret_key
89
132
  session_token = credentials_response.credentials.session_token
90
133
 
91
134
  @auth_data = {
92
- email: username,
135
+ email: params.email,
93
136
  access_key_id: access_key_id,
94
137
  secret_key: secret_key,
95
138
  region: "ap-southeast-2",
@@ -126,12 +169,12 @@ module SimplicityClient
126
169
  signature = signer.sign_request(
127
170
  http_method: http_method,
128
171
  url: url,
129
- body: body
172
+ body: body,
130
173
  )
131
174
 
132
175
  response = @client.post(url) do |req|
133
176
  req.headers = signature.headers.merge({
134
- 'Content-Type' => 'application/json'
177
+ "Content-Type" => "application/json",
135
178
  })
136
179
  req.body = body
137
180
  end
@@ -154,5 +197,76 @@ module SimplicityClient
154
197
  raise Error, "Failed to list accounts: #{response.status}, #{response.body}"
155
198
  end
156
199
  end
200
+
201
+ private
202
+
203
+ def fetch_challenge_id
204
+ response = @client.post("#{@authsignal_base}/client/challenge") do |req|
205
+ req.headers = {
206
+ "Authorization" => "Basic #{Base64.encode64(@authsignal_tenant_id)}",
207
+ "Content-Type" => "application/json",
208
+ }
209
+ req.body = {
210
+ action: "cognitoAuth",
211
+ }.to_json
212
+ end
213
+
214
+ if response.success?
215
+ obj = JSON.parse(response.body)
216
+ obj["challengeId"]
217
+ else
218
+ raise Error, "Failed to get challenge ID: #{response.status}, #{response.body}"
219
+ end
220
+ end
221
+
222
+ def fetch_authentication_options(challenge_id)
223
+ response = @client.post("#{@authsignal_base}/client/user-authenticators/passkey/authentication-options") do |req|
224
+ req.headers = {
225
+ "Authorization" => "Basic #{Base64.encode64(@authsignal_tenant_id)}",
226
+ "Content-Type" => "application/json",
227
+ }
228
+ req.body = {
229
+ challengeId: challenge_id,
230
+ }.to_json
231
+ end
232
+
233
+ if response.success?
234
+ JSON.parse(response.body)
235
+ else
236
+ raise Error, "Failed to get authentication options: #{response.status}, #{response.body}"
237
+ end
238
+ end
239
+
240
+ def present_passkey(challenge_id, assertion, device_id)
241
+ response = @client.post("#{@authsignal_base}/client/verify/passkey") do |req|
242
+ req.headers = {
243
+ "Authorization" => "Basic #{Base64.encode64(@authsignal_tenant_id)}",
244
+ "Content-Type" => "application/json",
245
+ }
246
+ req.body = {
247
+ challengeId: challenge_id,
248
+ authenticationCredential: {
249
+ id: assertion.credential_id,
250
+ rawId: assertion.credential_id,
251
+ response: {
252
+ authenticatorData: assertion.authenticator_data,
253
+ clientDataJSON: assertion.client_data_json,
254
+ signature: assertion.signature,
255
+ userHandle: assertion.user_handle,
256
+ },
257
+ type: "public-key",
258
+ clientExtensionResults: {},
259
+ authenticatorAttachment: "platform",
260
+ },
261
+ deviceId: device_id,
262
+ }.to_json
263
+ end
264
+
265
+ if response.success?
266
+ JSON.parse(response.body)
267
+ else
268
+ raise Error, "Failed to get JWT: #{response.status}, #{response.body}"
269
+ end
270
+ end
157
271
  end
158
272
  end
metadata CHANGED
@@ -1,113 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simplicity_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Dewar
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-02 00:00:00.000000000 Z
11
+ date: 2025-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: faraday
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.7'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.7'
27
- - !ruby/object:Gem::Dependency
28
- name: faraday-cookie_jar
14
+ name: aws-sdk-cognitoidentity
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - "~>"
32
18
  - !ruby/object:Gem::Version
33
- version: 0.0.7
19
+ version: 1.52.0
34
20
  type: :runtime
35
21
  prerelease: false
36
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
24
  - - "~>"
39
25
  - !ruby/object:Gem::Version
40
- version: 0.0.7
26
+ version: 1.52.0
41
27
  - !ruby/object:Gem::Dependency
42
- name: faraday-follow_redirects
28
+ name: aws-sdk-cognitoidentityprovider
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: 0.3.0
33
+ version: '1.87'
48
34
  type: :runtime
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: 0.3.0
40
+ version: '1.87'
55
41
  - !ruby/object:Gem::Dependency
56
- name: aws-sdk-cognitoidentityprovider
42
+ name: aws-sigv4
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '1.87'
47
+ version: 1.8.0
62
48
  type: :runtime
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '1.87'
54
+ version: 1.8.0
69
55
  - !ruby/object:Gem::Dependency
70
- name: aws-cognito-srp
56
+ name: faraday
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: 0.6.0
61
+ version: '2.7'
76
62
  type: :runtime
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: 0.6.0
68
+ version: '2.7'
83
69
  - !ruby/object:Gem::Dependency
84
- name: aws-sdk-cognitoidentity
70
+ name: faraday-cookie_jar
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: 1.52.0
75
+ version: 0.0.7
90
76
  type: :runtime
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: 1.52.0
82
+ version: 0.0.7
97
83
  - !ruby/object:Gem::Dependency
98
- name: aws-sigv4
84
+ name: faraday-follow_redirects
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
87
  - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: 1.8.0
89
+ version: 0.3.0
104
90
  type: :runtime
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
- version: 1.8.0
96
+ version: 0.3.0
111
97
  description: This gem can log into Simplicity and fetch fund balances
112
98
  email:
113
99
  - george@dewar.co.nz
@@ -116,11 +102,11 @@ extensions: []
116
102
  extra_rdoc_files: []
117
103
  files:
118
104
  - lib/simplicity_client.rb
119
- homepage: https://rubygems.org/gems/hola
105
+ homepage: https://github.com/GeorgeDewar/simplicity_client
120
106
  licenses:
121
107
  - MIT
122
108
  metadata: {}
123
- post_install_message:
109
+ post_install_message:
124
110
  rdoc_options: []
125
111
  require_paths:
126
112
  - lib
@@ -135,8 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
121
  - !ruby/object:Gem::Version
136
122
  version: '0'
137
123
  requirements: []
138
- rubygems_version: 3.2.3
139
- signing_key:
124
+ rubygems_version: 3.5.16
125
+ signing_key:
140
126
  specification_version: 4
141
127
  summary: Fetch KiwiSaver and investment fund balances from Simplicity
142
128
  test_files: []