simplicity_client 0.1.2 → 0.2.0

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 +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: []