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 +4 -4
- data/lib/fido2_client.rb +91 -0
- data/lib/simplicity_client.rb +37 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af805426700df49eb866015545dac1afa7c833490be0c0f2a6cb825bd9dc2e3e
|
4
|
+
data.tar.gz: 4dbeed2df67de9a27ff27c5521ad8b581f2e5f9b6642975612429eea7efa4f4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73e5c8d7f37681956ac2dcddb647522b1cae78d78e9d85c8744c7f0a96ee18c5740e62618365ca6cb7defcdd73de4094eb5870325690f170a42af8643cf4c57e
|
7
|
+
data.tar.gz: d6f3d25bf87442259549191a82c2d590f7d2cdcabe8b2deba838142da0f800a8c330bacc9e4bce9e553fc887310cb4bf8597b37b472e348c7d33ddd6bd6aa26d
|
data/lib/fido2_client.rb
ADDED
@@ -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
|
data/lib/simplicity_client.rb
CHANGED
@@ -155,7 +155,35 @@ module SimplicityClient
|
|
155
155
|
email = @auth_data["email"]
|
156
156
|
body = {
|
157
157
|
variables: {},
|
158
|
-
query:
|
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"]["
|
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:
|
188
|
-
accountType: "#{
|
189
|
-
customerName:
|
190
|
-
accountBalance:
|
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.
|
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-
|
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:
|