lara-sdk 1.0.6 → 1.0.9
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/lara/auth_token.rb +27 -0
- data/lib/lara/client.rb +46 -41
- data/lib/lara/errors.rb +4 -3
- data/lib/lara/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bec4d6b11a9be0d2481e0c83488befb4230e87cba9ec5d598f8ee397307b0c8c
|
|
4
|
+
data.tar.gz: 9db2905ef0db583ef555c1792d326369776c2508d2d5bdc3a75ff9176320c284
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b644e13aeb677fa3a95af224165f87d1b35fdaf7f356ad25d1fc803cd0e243641e99a25514e5cbfef15d110efb4bca232d69e92fff333348ce68794d4e9f6f3
|
|
7
|
+
data.tar.gz: 488de412d6562bbca3b8c6f9ba613da79150dccbdfdb58a1be4e1288ccaa8f3f060d6584c98b58ecb9e1802f12dae6b2ffa6e41b34ac52469c2a0aa3c9b1d271
|
data/lib/lara/auth_token.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "json"
|
|
4
|
+
require "base64"
|
|
5
|
+
|
|
3
6
|
module Lara
|
|
4
7
|
# JWT authentication token for API access
|
|
5
8
|
class AuthToken
|
|
@@ -8,10 +11,34 @@ module Lara
|
|
|
8
11
|
def initialize(token, refresh_token)
|
|
9
12
|
@token = token
|
|
10
13
|
@refresh_token = refresh_token
|
|
14
|
+
@expires_at_ms = parse_expires_at_ms(token)
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def to_s
|
|
14
18
|
token
|
|
15
19
|
end
|
|
20
|
+
|
|
21
|
+
def token_expired?
|
|
22
|
+
@expires_at_ms <= (Time.now.to_f * 1000).to_i + 5_000 # 5 seconds buffer
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def parse_expires_at_ms(token)
|
|
28
|
+
return 0 if token.nil? || token.empty?
|
|
29
|
+
|
|
30
|
+
parts = token.split(".")
|
|
31
|
+
return 0 if parts.length != 3
|
|
32
|
+
|
|
33
|
+
b64 = parts[1].tr("-_", "+/")
|
|
34
|
+
b64 += "=" * (4 - (b64.length % 4)) if b64.length % 4 != 0
|
|
35
|
+
|
|
36
|
+
exp = JSON.parse(Base64.decode64(b64))["exp"]
|
|
37
|
+
return 0 unless exp.is_a?(Numeric)
|
|
38
|
+
|
|
39
|
+
(exp * 1000).to_i
|
|
40
|
+
rescue StandardError
|
|
41
|
+
0
|
|
42
|
+
end
|
|
16
43
|
end
|
|
17
44
|
end
|
data/lib/lara/client.rb
CHANGED
|
@@ -7,6 +7,7 @@ require "openssl"
|
|
|
7
7
|
require "base64"
|
|
8
8
|
require "digest"
|
|
9
9
|
require "uri"
|
|
10
|
+
require "monitor"
|
|
10
11
|
|
|
11
12
|
module Lara
|
|
12
13
|
# This class is used to interact with Lara via the REST API.
|
|
@@ -31,7 +32,7 @@ module Lara
|
|
|
31
32
|
@connection_timeout = connection_timeout
|
|
32
33
|
@read_timeout = read_timeout
|
|
33
34
|
@extra_headers = {}
|
|
34
|
-
@auth_mutex =
|
|
35
|
+
@auth_mutex = Monitor.new
|
|
35
36
|
|
|
36
37
|
@connection = build_connection
|
|
37
38
|
end
|
|
@@ -93,23 +94,37 @@ module Lara
|
|
|
93
94
|
make_request(method, path, body: body, files: files, headers: headers, params: params,
|
|
94
95
|
raw_response: raw_response, &callback)
|
|
95
96
|
rescue LaraApiError => e
|
|
96
|
-
|
|
97
|
-
raise unless e.status_code == 401 && e.message.include?("jwt expired")
|
|
97
|
+
raise unless e.status_code == 401
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
# Retry once with new token
|
|
99
|
+
@auth_mutex.synchronize { refresh_or_reauthenticate }
|
|
101
100
|
make_request(method, path, body: body, files: files, headers: headers, params: params,
|
|
102
101
|
raw_response: raw_response, &callback)
|
|
103
102
|
end
|
|
104
103
|
|
|
105
104
|
def ensure_valid_token
|
|
106
105
|
@auth_mutex.synchronize do
|
|
107
|
-
return if @auth_token
|
|
106
|
+
return if @auth_token && !@auth_token.token_expired?
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
refresh_or_reauthenticate
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def refresh_or_reauthenticate
|
|
113
|
+
if @auth_token&.refresh_token && !@auth_token.refresh_token.empty?
|
|
114
|
+
begin
|
|
115
|
+
do_refresh
|
|
116
|
+
return
|
|
117
|
+
rescue StandardError
|
|
118
|
+
raise unless @credentials
|
|
119
|
+
end
|
|
120
|
+
end
|
|
110
121
|
|
|
122
|
+
if @credentials
|
|
111
123
|
@auth_token = authenticate
|
|
124
|
+
return
|
|
112
125
|
end
|
|
126
|
+
|
|
127
|
+
raise LaraError, "No authentication method available for token renewal"
|
|
113
128
|
end
|
|
114
129
|
|
|
115
130
|
def authenticate
|
|
@@ -143,47 +158,37 @@ module Lara
|
|
|
143
158
|
raise LaraApiError.from_response(response) unless response.success?
|
|
144
159
|
|
|
145
160
|
data = JSON.parse(response.body)
|
|
146
|
-
|
|
161
|
+
refresh_token_value = response.headers["x-lara-refresh-token"]
|
|
147
162
|
|
|
148
|
-
raise LaraError, "Missing refresh token in authentication response" unless
|
|
163
|
+
raise LaraError, "Missing refresh token in authentication response" unless refresh_token_value
|
|
149
164
|
|
|
150
|
-
AuthToken.new(data["token"],
|
|
165
|
+
AuthToken.new(data["token"], refresh_token_value)
|
|
151
166
|
end
|
|
152
167
|
|
|
153
|
-
def
|
|
154
|
-
@
|
|
155
|
-
return unless @auth_token
|
|
168
|
+
def do_refresh
|
|
169
|
+
raise LaraError, "No refresh token available" unless @auth_token&.refresh_token
|
|
156
170
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
response = conn.post("/v2/auth/refresh") do |req|
|
|
162
|
-
req.headers = {
|
|
163
|
-
"Date" => Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S GMT"),
|
|
164
|
-
"X-Lara-SDK-Name" => "lara-ruby",
|
|
165
|
-
"X-Lara-SDK-Version" => Lara::VERSION,
|
|
166
|
-
"Authorization" => "Bearer #{@auth_token&.refresh_token}"
|
|
167
|
-
}
|
|
168
|
-
end
|
|
171
|
+
conn = Faraday.new(url: @base_url) do |c|
|
|
172
|
+
c.adapter Faraday.default_adapter
|
|
173
|
+
end
|
|
169
174
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
# Refresh failed, force re-authentication
|
|
178
|
-
@auth_token = nil
|
|
179
|
-
ensure_valid_token
|
|
180
|
-
end
|
|
181
|
-
else
|
|
182
|
-
# Refresh failed, force re-authentication
|
|
183
|
-
@auth_token = nil
|
|
184
|
-
ensure_valid_token
|
|
185
|
-
end
|
|
175
|
+
response = conn.post("/v2/auth/refresh") do |req|
|
|
176
|
+
req.headers = {
|
|
177
|
+
"Date" => Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S GMT"),
|
|
178
|
+
"X-Lara-SDK-Name" => "lara-ruby",
|
|
179
|
+
"X-Lara-SDK-Version" => Lara::VERSION,
|
|
180
|
+
"Authorization" => "Bearer #{@auth_token.refresh_token}"
|
|
181
|
+
}
|
|
186
182
|
end
|
|
183
|
+
|
|
184
|
+
raise LaraApiError.from_response(response) unless response.success?
|
|
185
|
+
|
|
186
|
+
data = JSON.parse(response.body)
|
|
187
|
+
refresh_token_value = response.headers["x-lara-refresh-token"]
|
|
188
|
+
|
|
189
|
+
raise LaraError, "Missing refresh token in refresh response" unless refresh_token_value
|
|
190
|
+
|
|
191
|
+
@auth_token = AuthToken.new(data["token"], refresh_token_value)
|
|
187
192
|
end
|
|
188
193
|
|
|
189
194
|
def make_request(method, path, body: nil, files: nil, headers: nil, params: nil, raw_response: false, &callback)
|
data/lib/lara/errors.rb
CHANGED
|
@@ -17,15 +17,16 @@ module Lara
|
|
|
17
17
|
class LaraApiError < LaraError
|
|
18
18
|
attr_reader :type
|
|
19
19
|
|
|
20
|
-
# Builds an error from an HTTP response with JSON body
|
|
21
|
-
# { "error": { "type": "...", "message": "..." } }
|
|
20
|
+
# Builds an error from an HTTP response with JSON body.
|
|
21
|
+
# Supports both { "error": { "type": "...", "message": "..." } }
|
|
22
|
+
# and { "type": "...", "message": "..." } response formats.
|
|
22
23
|
def self.from_response(response)
|
|
23
24
|
data = begin
|
|
24
25
|
JSON.parse(response.body)
|
|
25
26
|
rescue StandardError
|
|
26
27
|
{}
|
|
27
28
|
end
|
|
28
|
-
error = data["error"] ||
|
|
29
|
+
error = data["error"] || data
|
|
29
30
|
error_type = error["type"] || "UnknownError"
|
|
30
31
|
error_message = error["message"] || "An unknown error occurred"
|
|
31
32
|
new(response.status, error_type, error_message)
|
data/lib/lara/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lara-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Translated
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|