tripwire-server 0.1.1 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +48 -13
- data/lib/tripwire/server/client.rb +171 -16
- data/lib/tripwire/server/crypto_support.rb +49 -0
- data/lib/tripwire/server/gate_delivery.rb +298 -0
- data/lib/tripwire/server/sealed_token.rb +2 -0
- data/lib/tripwire/server/version.rb +1 -1
- data/lib/tripwire/server.rb +12 -0
- data/spec/README.md +37 -6
- data/spec/fixtures/api/fingerprints/detail.json +70 -0
- data/spec/fixtures/api/fingerprints/list.json +37 -0
- data/spec/fixtures/api/gate/agent-token-verify.json +12 -0
- data/spec/fixtures/api/gate/login-session-consume.json +10 -0
- data/spec/fixtures/api/gate/login-session-create.json +12 -0
- data/spec/fixtures/api/gate/registry-detail.json +45 -0
- data/spec/fixtures/api/gate/registry-list.json +47 -0
- data/spec/fixtures/api/gate/service-create.json +49 -0
- data/spec/fixtures/api/gate/service-detail.json +49 -0
- data/spec/fixtures/api/gate/service-disable.json +49 -0
- data/spec/fixtures/api/gate/service-update.json +49 -0
- data/spec/fixtures/api/gate/services-list.json +51 -0
- data/spec/fixtures/api/gate/session-ack.json +10 -0
- data/spec/fixtures/api/gate/session-create.json +13 -0
- data/spec/fixtures/api/gate/session-poll.json +36 -0
- data/spec/fixtures/api/sessions/detail.json +405 -0
- data/spec/fixtures/api/sessions/list.json +36 -0
- data/spec/fixtures/api/teams/api-key-create.json +21 -0
- data/spec/fixtures/api/teams/api-key-list.json +26 -0
- data/spec/fixtures/api/teams/api-key-revoke.json +20 -0
- data/spec/fixtures/api/teams/api-key-rotate.json +21 -0
- data/spec/fixtures/api/teams/team-create.json +14 -0
- data/spec/fixtures/api/teams/team-update.json +14 -0
- data/spec/fixtures/api/teams/team.json +14 -0
- data/spec/fixtures/errors/invalid-api-key.json +3 -3
- data/spec/fixtures/errors/missing-api-key.json +2 -2
- data/spec/fixtures/errors/not-found.json +4 -4
- data/spec/fixtures/errors/validation-error.json +6 -7
- data/spec/fixtures/gate-delivery/approved-webhook-payload.valid.json +20 -0
- data/spec/fixtures/gate-delivery/delivery-request.json +9 -0
- data/spec/fixtures/gate-delivery/env-policy.json +40 -0
- data/spec/fixtures/gate-delivery/vector.v1.json +28 -0
- data/spec/fixtures/gate-delivery/webhook-signature.json +9 -0
- data/spec/fixtures/manifest.json +179 -0
- data/spec/fixtures/sealed-token/vector.v1.json +37 -24
- data/spec/openapi.json +4905 -779
- data/spec/sealed-token.md +36 -17
- metadata +36 -14
- data/spec/fixtures/public-api/fingerprints/detail.json +0 -40
- data/spec/fixtures/public-api/fingerprints/list.json +0 -31
- data/spec/fixtures/public-api/sessions/detail.json +0 -47
- data/spec/fixtures/public-api/sessions/list.json +0 -33
- data/spec/fixtures/public-api/teams/api-key-create.json +0 -18
- data/spec/fixtures/public-api/teams/api-key-list.json +0 -23
- data/spec/fixtures/public-api/teams/api-key-rotate.json +0 -18
- data/spec/fixtures/public-api/teams/team-create.json +0 -11
- data/spec/fixtures/public-api/teams/team-update.json +0 -11
- data/spec/fixtures/public-api/teams/team.json +0 -11
- /data/spec/fixtures/{public-api/teams/api-key-revoke.json → api/gate/agent-token-revoke.json} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 45e6986f12a591fdd4523c5564f2555d09c0729783e5d12998541e65652814d4
|
|
4
|
+
data.tar.gz: b7c767d8c99846ce42dfa6820dcf787a48cb36f0367ec302f636a55b706dfd0c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6bb732f690f751fd371ffcaccec4895f762a06685703715c92e35a1cbdd35d87dca706d6fcb5a5c8763e8bd9e26ca003e758d747dc724bdba2c21547922ce032
|
|
7
|
+
data.tar.gz: fe3def014d6b619cad9e3a07a1fc05a276b415231b30538afbf49d832bb5436f644cc9918a02aa1bea1a9a0fdae0cbc67c141d8e2d181bfd60da3d4eb0cebf7b
|
data/README.md
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
# Tripwire Ruby Library
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
The Tripwire Ruby library provides convenient access to the Tripwire API from applications written in Ruby. It includes a client for Sessions,
|
|
7
|
+
The Tripwire Ruby library provides convenient access to the Tripwire API from applications written in Ruby. It includes a client for Sessions, visitor fingerprints, Teams, Team API key management, sealed token verification, Gate, and Gate delivery/webhook helpers.
|
|
8
8
|
|
|
9
9
|
The library also provides:
|
|
10
10
|
|
|
11
11
|
- a fast configuration path using `TRIPWIRE_SECRET_KEY`
|
|
12
12
|
- lazy helpers for cursor-based pagination
|
|
13
13
|
- structured API errors and built-in sealed token verification
|
|
14
|
+
- public, bearer-token, and secret-key auth modes for Gate flows
|
|
15
|
+
- Gate delivery/webhook helpers
|
|
14
16
|
|
|
15
17
|
## Documentation
|
|
16
18
|
|
|
@@ -26,11 +28,11 @@ bundle add tripwire-server
|
|
|
26
28
|
|
|
27
29
|
## Requirements
|
|
28
30
|
|
|
29
|
-
- Ruby
|
|
31
|
+
- Ruby 3.3+
|
|
30
32
|
|
|
31
33
|
## Usage
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
Use `TRIPWIRE_SECRET_KEY` or `secret_key:` for core detect APIs. For public or bearer-auth Gate flows, the client can also be created without a secret key:
|
|
34
36
|
|
|
35
37
|
```ruby
|
|
36
38
|
require "tripwire/server"
|
|
@@ -38,7 +40,9 @@ require "tripwire/server"
|
|
|
38
40
|
client = Tripwire::Server::Client.new(secret_key: "sk_live_...")
|
|
39
41
|
|
|
40
42
|
page = client.sessions.list(verdict: "bot", limit: 25)
|
|
41
|
-
session = client.sessions.get("
|
|
43
|
+
session = client.sessions.get("sid_0123456789abcdefghjkmnpqrs")
|
|
44
|
+
|
|
45
|
+
puts "#{session[:decision][:automation_status]} #{session[:highlights].first&.fetch(:summary, nil)}"
|
|
42
46
|
```
|
|
43
47
|
|
|
44
48
|
### Sealed token verification
|
|
@@ -47,7 +51,7 @@ session = client.sessions.get("sid_123")
|
|
|
47
51
|
result = Tripwire::Server.safe_verify_tripwire_token(sealed_token, "sk_live_...")
|
|
48
52
|
|
|
49
53
|
if result[:ok]
|
|
50
|
-
puts "#{result[:data][:verdict]} #{result[:data][:
|
|
54
|
+
puts "#{result[:data][:decision][:verdict]} #{result[:data][:decision][:risk_score]}"
|
|
51
55
|
else
|
|
52
56
|
warn result[:error].message
|
|
53
57
|
end
|
|
@@ -57,22 +61,22 @@ end
|
|
|
57
61
|
|
|
58
62
|
```ruby
|
|
59
63
|
client.sessions.iter(search: "signup").each do |session|
|
|
60
|
-
puts "#{session[:id]} #{session[:
|
|
64
|
+
puts "#{session[:id]} #{session[:latest_decision][:verdict]}"
|
|
61
65
|
end
|
|
62
66
|
```
|
|
63
67
|
|
|
64
|
-
###
|
|
68
|
+
### Visitor fingerprints
|
|
65
69
|
|
|
66
70
|
```ruby
|
|
67
|
-
fingerprint = client.fingerprints.get("
|
|
71
|
+
fingerprint = client.fingerprints.get("vid_0123456789abcdefghjkmnpqrs")
|
|
68
72
|
puts fingerprint[:id]
|
|
69
73
|
```
|
|
70
74
|
|
|
71
75
|
### Teams
|
|
72
76
|
|
|
73
77
|
```ruby
|
|
74
|
-
team = client.teams.get("
|
|
75
|
-
updated = client.teams.update("
|
|
78
|
+
team = client.teams.get("team_0123456789abcdefghjkmnpqrs")
|
|
79
|
+
updated = client.teams.update("team_0123456789abcdefghjkmnpqrs", name: "New Name")
|
|
76
80
|
|
|
77
81
|
puts updated[:name]
|
|
78
82
|
```
|
|
@@ -80,8 +84,39 @@ puts updated[:name]
|
|
|
80
84
|
### Team API keys
|
|
81
85
|
|
|
82
86
|
```ruby
|
|
83
|
-
created = client.teams.api_keys.create("
|
|
84
|
-
client.teams.api_keys.revoke("
|
|
87
|
+
created = client.teams.api_keys.create("team_0123456789abcdefghjkmnpqrs", name: "Production", environment: "live")
|
|
88
|
+
client.teams.api_keys.revoke("team_0123456789abcdefghjkmnpqrs", created[:id])
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Gate APIs
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
delivery_key_pair = Tripwire::Server::GateDelivery.create_delivery_key_pair
|
|
95
|
+
|
|
96
|
+
services = client.gate.registry.list
|
|
97
|
+
session = client.gate.sessions.create(
|
|
98
|
+
service_id: "tripwire",
|
|
99
|
+
account_name: "my-project",
|
|
100
|
+
delivery: delivery_key_pair[:delivery]
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
puts "#{services.first[:id]} #{session[:consent_url]}"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Gate delivery and webhook helpers
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
key_pair = Tripwire::Server::GateDelivery.create_delivery_key_pair
|
|
110
|
+
response = Tripwire::Server::GateDelivery.create_gate_approved_webhook_response(
|
|
111
|
+
delivery: key_pair[:delivery],
|
|
112
|
+
outputs: {
|
|
113
|
+
"TRIPWIRE_PUBLISHABLE_KEY" => "pk_live_...",
|
|
114
|
+
"TRIPWIRE_SECRET_KEY" => "sk_live_..."
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
payload = Tripwire::Server::GateDelivery.decrypt_gate_delivery_envelope(key_pair[:private_key], response[:encrypted_delivery])
|
|
118
|
+
|
|
119
|
+
puts payload[:outputs]["TRIPWIRE_SECRET_KEY"]
|
|
85
120
|
```
|
|
86
121
|
|
|
87
122
|
### Error handling
|
|
@@ -10,11 +10,9 @@ module Tripwire
|
|
|
10
10
|
DEFAULT_TIMEOUT = 30
|
|
11
11
|
SDK_CLIENT_HEADER = "tripwire-server-ruby/0.1.0".freeze
|
|
12
12
|
|
|
13
|
-
attr_reader :sessions, :fingerprints, :teams, :timeout
|
|
13
|
+
attr_reader :sessions, :fingerprints, :teams, :gate, :timeout
|
|
14
14
|
|
|
15
15
|
def initialize(secret_key: ENV["TRIPWIRE_SECRET_KEY"], base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT, user_agent: nil, transport: nil)
|
|
16
|
-
raise ConfigurationError, "Missing Tripwire secret key. Pass secret_key explicitly or set TRIPWIRE_SECRET_KEY." if secret_key.nil? || secret_key.empty?
|
|
17
|
-
|
|
18
16
|
@secret_key = secret_key
|
|
19
17
|
@base_url = base_url
|
|
20
18
|
@timeout = timeout
|
|
@@ -24,17 +22,18 @@ module Tripwire
|
|
|
24
22
|
@sessions = SessionsResource.new(self)
|
|
25
23
|
@fingerprints = FingerprintsResource.new(self)
|
|
26
24
|
@teams = TeamsResource.new(self)
|
|
25
|
+
@gate = GateResource.new(self)
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
def request_json(method, path, query: {}, body: nil, expect_content: true)
|
|
28
|
+
def request_json(method, path, query: {}, body: nil, expect_content: true, auth: { kind: :secret })
|
|
30
29
|
url = build_url(path, query)
|
|
31
30
|
headers = {
|
|
32
|
-
"Authorization" => "Bearer #{@secret_key}",
|
|
33
31
|
"Accept" => "application/json",
|
|
34
32
|
"X-Tripwire-Client" => SDK_CLIENT_HEADER
|
|
35
33
|
}
|
|
36
34
|
headers["User-Agent"] = @user_agent if @user_agent
|
|
37
35
|
headers["Content-Type"] = "application/json" if body
|
|
36
|
+
apply_auth_headers(headers, auth)
|
|
38
37
|
|
|
39
38
|
status, response_headers, response_body =
|
|
40
39
|
if @transport
|
|
@@ -54,9 +53,9 @@ module Tripwire
|
|
|
54
53
|
status: status,
|
|
55
54
|
code: error[:code] || "request.failed",
|
|
56
55
|
message: error[:message] || response_body.to_s,
|
|
57
|
-
request_id: request_id || error[:
|
|
58
|
-
field_errors: details[:
|
|
59
|
-
docs_url: error[:
|
|
56
|
+
request_id: request_id || error[:request_id],
|
|
57
|
+
field_errors: details[:fields] || [],
|
|
58
|
+
docs_url: error[:docs_url],
|
|
60
59
|
body: payload
|
|
61
60
|
)
|
|
62
61
|
end
|
|
@@ -125,6 +124,24 @@ module Tripwire
|
|
|
125
124
|
end
|
|
126
125
|
end
|
|
127
126
|
private :deep_symbolize
|
|
127
|
+
|
|
128
|
+
def apply_auth_headers(headers, auth)
|
|
129
|
+
kind = (auth[:kind] || :secret).to_sym
|
|
130
|
+
case kind
|
|
131
|
+
when :none
|
|
132
|
+
headers
|
|
133
|
+
when :bearer
|
|
134
|
+
token = auth[:token]
|
|
135
|
+
raise ConfigurationError, "Missing bearer token for this Tripwire request." if token.nil? || token.empty?
|
|
136
|
+
|
|
137
|
+
headers["Authorization"] = "Bearer #{token}"
|
|
138
|
+
else
|
|
139
|
+
raise ConfigurationError, "Missing Tripwire secret key. Pass secret_key explicitly or set TRIPWIRE_SECRET_KEY." if @secret_key.nil? || @secret_key.empty?
|
|
140
|
+
|
|
141
|
+
headers["Authorization"] = "Bearer #{@secret_key}"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
private :apply_auth_headers
|
|
128
145
|
end
|
|
129
146
|
|
|
130
147
|
class BaseResource
|
|
@@ -138,8 +155,8 @@ module Tripwire
|
|
|
138
155
|
ListResult.new(
|
|
139
156
|
items: payload[:data],
|
|
140
157
|
limit: payload.fetch(:pagination).fetch(:limit),
|
|
141
|
-
has_more: payload.fetch(:pagination).fetch(:
|
|
142
|
-
next_cursor: payload.fetch(:pagination)[:
|
|
158
|
+
has_more: payload.fetch(:pagination).fetch(:has_more),
|
|
159
|
+
next_cursor: payload.fetch(:pagination)[:next_cursor]
|
|
143
160
|
)
|
|
144
161
|
end
|
|
145
162
|
end
|
|
@@ -203,12 +220,12 @@ module Tripwire
|
|
|
203
220
|
end
|
|
204
221
|
|
|
205
222
|
class ApiKeysResource < BaseResource
|
|
206
|
-
def create(team_id, name: nil,
|
|
223
|
+
def create(team_id, name: nil, environment: nil, allowed_origins: nil, rate_limit: nil)
|
|
207
224
|
payload = @client.request_json("POST", "/v1/teams/#{CGI.escape(team_id)}/api-keys", body: compact({
|
|
208
225
|
name: name,
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
226
|
+
environment: environment,
|
|
227
|
+
allowed_origins: allowed_origins,
|
|
228
|
+
rate_limit: rate_limit
|
|
212
229
|
}))
|
|
213
230
|
payload[:data]
|
|
214
231
|
end
|
|
@@ -222,8 +239,7 @@ module Tripwire
|
|
|
222
239
|
end
|
|
223
240
|
|
|
224
241
|
def revoke(team_id, key_id)
|
|
225
|
-
@client.request_json("DELETE", "/v1/teams/#{CGI.escape(team_id)}/api-keys/#{CGI.escape(key_id)}"
|
|
226
|
-
nil
|
|
242
|
+
@client.request_json("DELETE", "/v1/teams/#{CGI.escape(team_id)}/api-keys/#{CGI.escape(key_id)}")[:data]
|
|
227
243
|
end
|
|
228
244
|
|
|
229
245
|
def rotate(team_id, key_id)
|
|
@@ -261,5 +277,144 @@ module Tripwire
|
|
|
261
277
|
}.reject { |_key, value| value.nil? })[:data]
|
|
262
278
|
end
|
|
263
279
|
end
|
|
280
|
+
|
|
281
|
+
class GateResource < BaseResource
|
|
282
|
+
attr_reader :registry, :services, :sessions, :login_sessions, :agent_tokens
|
|
283
|
+
|
|
284
|
+
def initialize(client)
|
|
285
|
+
super(client)
|
|
286
|
+
@registry = GateRegistryResource.new(client)
|
|
287
|
+
@services = GateServicesResource.new(client)
|
|
288
|
+
@sessions = GateSessionsResource.new(client)
|
|
289
|
+
@login_sessions = GateLoginSessionsResource.new(client)
|
|
290
|
+
@agent_tokens = GateAgentTokensResource.new(client)
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
class GateRegistryResource < BaseResource
|
|
295
|
+
def list
|
|
296
|
+
@client.request_json("GET", "/v1/gate/registry", auth: { kind: :none })[:data]
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def get(service_id)
|
|
300
|
+
@client.request_json("GET", "/v1/gate/registry/#{CGI.escape(service_id)}", auth: { kind: :none })[:data]
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
class GateServicesResource < BaseResource
|
|
305
|
+
def list
|
|
306
|
+
@client.request_json("GET", "/v1/gate/services")[:data]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def get(service_id)
|
|
310
|
+
@client.request_json("GET", "/v1/gate/services/#{CGI.escape(service_id)}")[:data]
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def create(id:, name:, description:, website:, webhook_url:, discoverable: nil, dashboard_login_url: nil, webhook_secret: nil, env_vars: nil, docs_url: nil, sdks: nil, branding: nil, consent: nil)
|
|
314
|
+
@client.request_json("POST", "/v1/gate/services", body: compact({
|
|
315
|
+
id: id,
|
|
316
|
+
discoverable: discoverable,
|
|
317
|
+
name: name,
|
|
318
|
+
description: description,
|
|
319
|
+
website: website,
|
|
320
|
+
dashboard_login_url: dashboard_login_url,
|
|
321
|
+
webhook_url: webhook_url,
|
|
322
|
+
webhook_secret: webhook_secret,
|
|
323
|
+
env_vars: env_vars,
|
|
324
|
+
docs_url: docs_url,
|
|
325
|
+
sdks: sdks,
|
|
326
|
+
branding: branding,
|
|
327
|
+
consent: consent
|
|
328
|
+
}))[:data]
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def update(service_id, discoverable: nil, name: nil, description: nil, website: nil, dashboard_login_url: nil, webhook_url: nil, webhook_secret: nil, env_vars: nil, docs_url: nil, sdks: nil, branding: nil, consent: nil)
|
|
332
|
+
@client.request_json("PATCH", "/v1/gate/services/#{CGI.escape(service_id)}", body: compact({
|
|
333
|
+
discoverable: discoverable,
|
|
334
|
+
name: name,
|
|
335
|
+
description: description,
|
|
336
|
+
website: website,
|
|
337
|
+
dashboard_login_url: dashboard_login_url,
|
|
338
|
+
webhook_url: webhook_url,
|
|
339
|
+
webhook_secret: webhook_secret,
|
|
340
|
+
env_vars: env_vars,
|
|
341
|
+
docs_url: docs_url,
|
|
342
|
+
sdks: sdks,
|
|
343
|
+
branding: branding,
|
|
344
|
+
consent: consent
|
|
345
|
+
}))[:data]
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def disable(service_id)
|
|
349
|
+
@client.request_json("DELETE", "/v1/gate/services/#{CGI.escape(service_id)}")[:data]
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
private
|
|
353
|
+
|
|
354
|
+
def compact(hash)
|
|
355
|
+
hash.reject { |_key, value| value.nil? }
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
class GateSessionsResource < BaseResource
|
|
360
|
+
def create(service_id:, account_name:, delivery:, metadata: nil)
|
|
361
|
+
body = {
|
|
362
|
+
service_id: service_id,
|
|
363
|
+
account_name: account_name,
|
|
364
|
+
delivery: delivery
|
|
365
|
+
}
|
|
366
|
+
body[:metadata] = metadata unless metadata.nil?
|
|
367
|
+
|
|
368
|
+
@client.request_json("POST", "/v1/gate/sessions", body: body, auth: { kind: :none })[:data]
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def poll(gate_session_id, poll_token:)
|
|
372
|
+
@client.request_json(
|
|
373
|
+
"GET",
|
|
374
|
+
"/v1/gate/sessions/#{CGI.escape(gate_session_id)}",
|
|
375
|
+
auth: { kind: :bearer, token: poll_token }
|
|
376
|
+
)[:data]
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def acknowledge(gate_session_id, poll_token:, ack_token:)
|
|
380
|
+
@client.request_json(
|
|
381
|
+
"POST",
|
|
382
|
+
"/v1/gate/sessions/#{CGI.escape(gate_session_id)}/ack",
|
|
383
|
+
body: { ack_token: ack_token },
|
|
384
|
+
auth: { kind: :bearer, token: poll_token }
|
|
385
|
+
)[:data]
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
class GateLoginSessionsResource < BaseResource
|
|
390
|
+
def create(service_id:, agent_token:)
|
|
391
|
+
@client.request_json(
|
|
392
|
+
"POST",
|
|
393
|
+
"/v1/gate/login-sessions",
|
|
394
|
+
body: { service_id: service_id },
|
|
395
|
+
auth: { kind: :bearer, token: agent_token }
|
|
396
|
+
)[:data]
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def consume(code:)
|
|
400
|
+
@client.request_json("POST", "/v1/gate/login-sessions/consume", body: { code: code })[:data]
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
class GateAgentTokensResource < BaseResource
|
|
405
|
+
def verify(agent_token:)
|
|
406
|
+
@client.request_json("POST", "/v1/gate/agent-tokens/verify", body: { agent_token: agent_token })[:data]
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def revoke(agent_token:)
|
|
410
|
+
@client.request_json(
|
|
411
|
+
"POST",
|
|
412
|
+
"/v1/gate/agent-tokens/revoke",
|
|
413
|
+
body: { agent_token: agent_token },
|
|
414
|
+
expect_content: false
|
|
415
|
+
)
|
|
416
|
+
nil
|
|
417
|
+
end
|
|
418
|
+
end
|
|
264
419
|
end
|
|
265
420
|
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require "openssl"
|
|
2
|
+
require "rubygems"
|
|
3
|
+
|
|
4
|
+
module Tripwire
|
|
5
|
+
module Server
|
|
6
|
+
module CryptoSupport
|
|
7
|
+
MIN_SUPPORTED_RUBY_VERSION = Gem::Version.new("3.3.0")
|
|
8
|
+
UNSUPPORTED_RUNTIME_MESSAGE = "Tripwire Ruby cryptography helpers require Ruby 3.3+ with modern OpenSSL support.".freeze
|
|
9
|
+
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def supported_runtime?
|
|
13
|
+
return @supported_runtime unless @supported_runtime.nil?
|
|
14
|
+
|
|
15
|
+
@supported_runtime = Gem::Version.new(RUBY_VERSION) >= MIN_SUPPORTED_RUBY_VERSION &&
|
|
16
|
+
OpenSSL::PKey.respond_to?(:generate_key) &&
|
|
17
|
+
defined?(OpenSSL::KDF) &&
|
|
18
|
+
OpenSSL::KDF.respond_to?(:hkdf) &&
|
|
19
|
+
aead_auth_data_supported?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ensure_supported_runtime!
|
|
23
|
+
return if supported_runtime?
|
|
24
|
+
|
|
25
|
+
raise ConfigurationError, UNSUPPORTED_RUNTIME_MESSAGE
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def minimum_supported_ruby_version
|
|
29
|
+
MIN_SUPPORTED_RUBY_VERSION
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def unsupported_runtime_message
|
|
33
|
+
UNSUPPORTED_RUNTIME_MESSAGE
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def aead_auth_data_supported?
|
|
37
|
+
cipher = OpenSSL::Cipher.new("aes-256-gcm")
|
|
38
|
+
cipher.encrypt
|
|
39
|
+
cipher.key = "\x00".b * 32
|
|
40
|
+
cipher.iv = "\x00".b * 12
|
|
41
|
+
cipher.auth_data = "".b
|
|
42
|
+
true
|
|
43
|
+
rescue StandardError
|
|
44
|
+
false
|
|
45
|
+
end
|
|
46
|
+
private_class_method :aead_auth_data_supported?
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|