simplicity_client 0.2.0 → 0.2.2

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: 35ccb4c05970e3765687119f1761b0c1ff47965ab6311f5e86e5fb321b8e87fd
4
- data.tar.gz: dfc4d51cf8d179a2901c62aaa576828193ddf6ef87a9aba6793da75da6825737
3
+ metadata.gz: af805426700df49eb866015545dac1afa7c833490be0c0f2a6cb825bd9dc2e3e
4
+ data.tar.gz: 4dbeed2df67de9a27ff27c5521ad8b581f2e5f9b6642975612429eea7efa4f4f
5
5
  SHA512:
6
- metadata.gz: 6ef0ea4b00d2ae9ae5deaaf317759fe595e7221fbfe46175c48747355e388ab4faaf4f0b272ccd6c57ec7c11fc7f06037dd35b6f9e76998c8258d36a6c406dfb
7
- data.tar.gz: 6c7618d98c48fc47adfa19931cb68a1fe67d612cc17e1e51c0a6cfdd7d708cffedf7dffd3ff96e425a890990c2b56d629541184edb033de49e2634d49f1e5be4
6
+ metadata.gz: 73e5c8d7f37681956ac2dcddb647522b1cae78d78e9d85c8744c7f0a96ee18c5740e62618365ca6cb7defcdd73de4094eb5870325690f170a42af8643cf4c57e
7
+ data.tar.gz: d6f3d25bf87442259549191a82c2d590f7d2cdcabe8b2deba838142da0f800a8c330bacc9e4bce9e553fc887310cb4bf8597b37b472e348c7d33ddd6bd6aa26d
@@ -0,0 +1,91 @@
1
+ require "json"
2
+ require "digest"
3
+ require "openssl"
4
+ require "base64"
5
+
6
+ module Fido2Client
7
+ Passkey = Data.define(:credentialId, :keyAlgorithm, :keyCurve, :keyValue, :userHandle)
8
+ Assertion = Data.define(:authenticator_data, :client_data_json, :credential_id, :user_handle, :signature)
9
+
10
+ class Client
11
+ def initialize
12
+ @origin = "https://app.simplicity.kiwi"
13
+ @rp_id = "simplicity.kiwi"
14
+ end
15
+
16
+ def get_assertion(passkey, challenge)
17
+ collected_client_data = {
18
+ type: "webauthn.get",
19
+ challenge: challenge,
20
+ origin: @origin,
21
+ crossOrigin: false,
22
+ }
23
+ client_data_json = JSON.dump(collected_client_data)
24
+ client_data_hash = Digest::SHA256.digest(client_data_json)
25
+
26
+ # Assertion
27
+ auth_data = generate_auth_data
28
+ private_key = parse_private_key(passkey.keyAlgorithm, passkey.keyCurve, passkey.keyValue)
29
+ signature = generate_signature(auth_data, client_data_hash, private_key)
30
+
31
+ Assertion.new(
32
+ authenticator_data: Base64.urlsafe_encode64(auth_data.pack("c*"), padding: false),
33
+ client_data_json: Base64.urlsafe_encode64(client_data_json, padding: false),
34
+ credential_id: Base64.urlsafe_encode64(guid_to_raw_format(passkey.credentialId), padding: false),
35
+ user_handle: passkey.userHandle,
36
+ signature: Base64.urlsafe_encode64(signature, padding: false),
37
+ )
38
+ end
39
+
40
+ private
41
+
42
+ def box(tag, lines)
43
+ lines.unshift "-----BEGIN #{tag}-----"
44
+ lines.push "-----END #{tag}-----"
45
+ lines.join("\n")
46
+ end
47
+
48
+ def der_to_pem(tag, der)
49
+ box tag, Base64.strict_encode64(der).scan(/.{1,64}/)
50
+ end
51
+
52
+ def parse_private_key(key_algorithm, key_curve, key_value)
53
+ raise "Unsupported key algorithm: #{key_algorithm}" unless key_algorithm == "ECDSA"
54
+ raise "Unsupported key curve: #{key_curve}" unless key_curve == "P-256"
55
+
56
+ # Decode the Base64 key value
57
+ key_value_bin = Base64.urlsafe_decode64(key_value)
58
+
59
+ pem = der_to_pem("PRIVATE KEY", key_value_bin)
60
+ OpenSSL::PKey::EC.new(pem)
61
+ end
62
+
63
+ def generate_signature(auth_data, client_data_hash, private_key)
64
+ sig_base = [*auth_data, *client_data_hash.bytes]
65
+ digest = OpenSSL::Digest.new("SHA256")
66
+ private_key.sign(digest, sig_base.pack("c*"))
67
+ end
68
+
69
+ def generate_auth_data
70
+ auth_data = []
71
+ rp_id_hash = Digest::SHA256.digest(@rp_id)
72
+ auth_data += rp_id_hash.bytes
73
+
74
+ # Flags asserted: Backup eligibility, Backup State, User Verification, User Presence
75
+ flags = 0x1D
76
+ auth_data.push(flags)
77
+
78
+ # Counter
79
+ auth_data += [0, 0, 0, 0]
80
+
81
+ auth_data
82
+ end
83
+
84
+ def guid_to_raw_format(guid)
85
+ raise TypeError, "GUID parameter is invalid" unless guid.match?(/\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/)
86
+
87
+ # Remove the hyphens and pack the string into raw binary
88
+ [guid.delete("-")].pack("H*")
89
+ end
90
+ end
91
+ end
@@ -155,7 +155,35 @@ module SimplicityClient
155
155
  email = @auth_data["email"]
156
156
  body = {
157
157
  variables: {},
158
- query: "{\n Account(email: \"#{email}\") {\n InvestmentType\n InvestmentCode\n PortfolioCode\n InvestmentName\n Portfolio\n Status\n RegistryAccountId\n MarketValue\n PrimaryBeneficiarySurname\n EntityType\n PriceDate\n IsDefault\n ExternalReference\n BankAccounts {\n AccountName\n LastThreeDigitsOfAccountNumberPart\n SuffixPart\n IsPrimary\n Id\n __typename\n }\n __typename\n }\n}\n",
158
+ query: <<-GRAPHQL
159
+ {
160
+ AccountV2(email: \"george@dewar.co.nz\") {
161
+ Portfolios {
162
+ Portfolio
163
+ PortfolioCode
164
+ MarketValue
165
+ IsDefault
166
+ CanWithdraw
167
+ InvestorDetails {
168
+ InvestmentName
169
+ PrimaryBeneficiarySurname
170
+ EntityType
171
+ __typename
172
+ }
173
+ __typename
174
+ }
175
+ Investment {
176
+ InvestmentCode
177
+ InvestmentType
178
+ Status
179
+ PriceDate
180
+ ExternalReference
181
+ __typename
182
+ }
183
+ __typename
184
+ }
185
+ }
186
+ GRAPHQL
159
187
  }.to_json
160
188
 
161
189
  signer = Aws::Sigv4::Signer.new(
@@ -182,12 +210,15 @@ module SimplicityClient
182
210
  # Handle the response
183
211
  if response.success?
184
212
  obj = JSON.parse(response.body)
185
- obj["data"]["Account"].map do |account|
213
+ obj["data"]["AccountV2"].map do |account|
214
+ investment = account["Investment"]
215
+ portfolio = account["Portfolios"][0]
216
+ investor_details = portfolio["InvestorDetails"]
186
217
  {
187
- accountNo: account["InvestmentCode"],
188
- accountType: "#{account["InvestmentType"]} - #{account["Portfolio"]}",
189
- customerName: account["InvestmentName"],
190
- accountBalance: account["MarketValue"],
218
+ accountNo: investment["InvestmentCode"],
219
+ accountType: "#{investment["InvestmentType"]} - #{portfolio["Portfolio"]}",
220
+ customerName: investor_details["InvestmentName"],
221
+ accountBalance: portfolio["MarketValue"],
191
222
  isLiabilityType: false,
192
223
  supportsTransactions: false,
193
224
  dynamicBalance: true,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simplicity_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Dewar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-03 00:00:00.000000000 Z
11
+ date: 2025-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-cognitoidentity
@@ -101,6 +101,7 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - lib/fido2_client.rb
104
105
  - lib/simplicity_client.rb
105
106
  homepage: https://github.com/GeorgeDewar/simplicity_client
106
107
  licenses: