end_point_blank 0.13.0 → 0.13.1
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/CHANGELOG.md +35 -0
- data/README.md +10 -0
- data/lib/end_point_blank/management/client.rb +5 -3
- data/lib/end_point_blank/management/error_codes.rb +4 -1
- data/lib/end_point_blank/management/resources/clients.rb +10 -2
- data/lib/end_point_blank/rack/headers.rb +27 -1
- data/lib/end_point_blank/version.rb +1 -1
- data/lib/end_point_blank/writers/request_writer.rb +3 -1
- data/lib/end_point_blank/writers/response_writer.rb +4 -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: 14c18a9f81130c9ec607b05a25aa5a4a67d9726c6692eb313a395734ce79bcf3
|
|
4
|
+
data.tar.gz: 4081ad91a0c10503521993a7d2d7887cd0810faab8b8f22229a57f9ed7685749
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 181770dadb24b746868274196d0600ff58d92ad7e430f2165b8ff7f59e376a0790ed027b9a8fb000b607b20698190755f5de5525ca78d540c198addab72c5fdd
|
|
7
|
+
data.tar.gz: 88593bf5bb77615e05d9277de7a4b167d5885a155cb9b30cfac83dbe0335003e84801abe7b826fe55ab81793b8990e0d39578bb05b2033bef2512a4cc5c11d6f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.1
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
- **Request and response records no longer carry credentials or cookies
|
|
8
|
+
(sc-1470).** Both records carried every `HTTP_*` header of the request (the
|
|
9
|
+
response record sends the request's headers, not the response's), so unless
|
|
10
|
+
you had written a masking rule for it, a caller's `Authorization` header
|
|
11
|
+
(Basic `client_id:secret` or a bearer token) landed in your request and
|
|
12
|
+
response logs in EndPointBlank. `RequestWriter` and `ResponseWriter` now
|
|
13
|
+
leave out `Authorization`, `Proxy-Authorization`, `Cookie` and `Set-Cookie`,
|
|
14
|
+
in any letter case, before masking runs, so they are not in the payload the
|
|
15
|
+
rules and hook receive, and they are not sent at all. The list is
|
|
16
|
+
`EndPointBlank::Rack::Headers::SENSITIVE_HEADERS`; the SDK's own reads of
|
|
17
|
+
the request (`Headers.extract`, used to find the endpoint version) are
|
|
18
|
+
unchanged. A masking rule that targeted one of these headers now has nothing
|
|
19
|
+
to match and can be removed. Records sent by earlier versions may hold these
|
|
20
|
+
values; rotate any client secret a caller sent while it was in use.
|
|
21
|
+
|
|
22
|
+
### Upgrading
|
|
23
|
+
|
|
24
|
+
- A `mask_hook` that reads `Authorization`, `Proxy-Authorization`, `Cookie` or
|
|
25
|
+
`Set-Cookie` from `headers` now finds it absent; guard the lookup.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **`claim_invite` takes an optional `return_to` (sc-1515).**
|
|
30
|
+
`clients.claim_invite(client_id, email:, return_to:)` and a managed
|
|
31
|
+
client's `claim_invite(email:, return_to:)` send `return_to`, where
|
|
32
|
+
EndPointBlank sends the customer's browser once they have claimed the
|
|
33
|
+
managed client. It is sent only when given, and must equal, byte for byte,
|
|
34
|
+
a claim return URL your organization registered in EndPointBlank; anything
|
|
35
|
+
else is refused with `return_to_not_registered` (422), now in
|
|
36
|
+
`ErrorCodes` as `RETURN_TO_NOT_REGISTERED`.
|
|
37
|
+
|
|
3
38
|
## 0.13.0
|
|
4
39
|
|
|
5
40
|
### Added
|
data/README.md
CHANGED
|
@@ -485,6 +485,11 @@ regex is applied only within the path-selected node(s). When a `regex` is presen
|
|
|
485
485
|
match; `$$` for a literal `$`). Stacktraces and log messages/data are never masked (there is no
|
|
486
486
|
`log` entry in the masking field map).
|
|
487
487
|
|
|
488
|
+
**Credential and cookie headers are never sent.** Before any rule runs, the request and response
|
|
489
|
+
records leave out `Authorization`, `Proxy-Authorization`, `Cookie` and `Set-Cookie`, whatever
|
|
490
|
+
their letter case. They are left out of the record, not masked: they are not in the payload the
|
|
491
|
+
rules and hook receive. The list is `EndPointBlank::Rack::Headers::SENSITIVE_HEADERS`.
|
|
492
|
+
|
|
488
493
|
## Framework integration
|
|
489
494
|
|
|
490
495
|
### Rails
|
|
@@ -670,6 +675,11 @@ mgmt.package_assignments.assign(customer["id"], api_package_id: package["id"], e
|
|
|
670
675
|
|
|
671
676
|
# ... and hand it over: the customer gets an email, and claiming rotates every credential you issued.
|
|
672
677
|
initech.claim_invite(email: "it@initech.example")
|
|
678
|
+
|
|
679
|
+
# Optionally send the customer's browser somewhere once they have claimed it. `return_to` must
|
|
680
|
+
# equal, byte for byte, a claim return URL your organization registered in EndPointBlank;
|
|
681
|
+
# anything else is refused with `return_to_not_registered` (422).
|
|
682
|
+
initech.claim_invite(email: "it@initech.example", return_to: "https://app.example/welcome")
|
|
673
683
|
```
|
|
674
684
|
|
|
675
685
|
Once claimed, the managed client's calls answer `not_found`. Remove an unclaimed one with
|
|
@@ -215,9 +215,11 @@ module EndPointBlank
|
|
|
215
215
|
end
|
|
216
216
|
|
|
217
217
|
# POST /clients/:client_id/claim_invites: emails your customer an
|
|
218
|
-
# invite to claim the client
|
|
219
|
-
|
|
220
|
-
|
|
218
|
+
# invite to claim the client, and with +return_to+ (a claim return URL
|
|
219
|
+
# your organization registered) where to send them once claimed; see
|
|
220
|
+
# {Resources::Clients#claim_invite}. @return [Hash]
|
|
221
|
+
def claim_invite(email:, return_to: nil, idempotency_key: nil)
|
|
222
|
+
@clients.claim_invite(client_id, email: email, return_to: return_to, idempotency_key: idempotency_key)
|
|
221
223
|
end
|
|
222
224
|
|
|
223
225
|
def inspect
|
|
@@ -66,6 +66,9 @@ module EndPointBlank
|
|
|
66
66
|
ENVIRONMENT_NOT_IN_APPLICATION = "environment_not_in_application"
|
|
67
67
|
ALREADY_GRANTED = "already_granted"
|
|
68
68
|
GRANT_REVOKED_CONCURRENTLY = "grant_revoked_concurrently"
|
|
69
|
+
# A claim invite's +return_to+ is not one of the claim return URLs your
|
|
70
|
+
# organization registered.
|
|
71
|
+
RETURN_TO_NOT_REGISTERED = "return_to_not_registered"
|
|
69
72
|
|
|
70
73
|
# The warning code API package endpoint writes answer in +warnings+ (not
|
|
71
74
|
# an error): a client assignment of the package now derives no grant.
|
|
@@ -97,7 +100,7 @@ module EndPointBlank
|
|
|
97
100
|
ALREADY_A_MEMBER => 422, MANAGED_CLIENT_HAS_CREDENTIALS => 422, API_PACKAGE_NOT_FOUND => 422,
|
|
98
101
|
ENVIRONMENT_NOT_FOUND => 422, ALREADY_ASSIGNED => 422, NOTHING_PUBLISHED_IN_ENVIRONMENT => 422,
|
|
99
102
|
APPLICATION_NOT_FOUND => 422, ENDPOINT_NOT_FOUND => 422, ENVIRONMENT_NOT_IN_APPLICATION => 422,
|
|
100
|
-
ALREADY_GRANTED => 422, GRANT_REVOKED_CONCURRENTLY => 409
|
|
103
|
+
ALREADY_GRANTED => 422, GRANT_REVOKED_CONCURRENTLY => 409, RETURN_TO_NOT_REGISTERED => 422
|
|
101
104
|
}.freeze
|
|
102
105
|
|
|
103
106
|
# Every code the API can send, as strings.
|
|
@@ -70,9 +70,17 @@ module EndPointBlank
|
|
|
70
70
|
|
|
71
71
|
# POST /clients/:client_id/claim_invites: emails your customer an
|
|
72
72
|
# invite to claim a managed client.
|
|
73
|
+
#
|
|
74
|
+
# +return_to+ (optional, sent only when given) is where EndPointBlank
|
|
75
|
+
# sends the customer's browser once they have claimed it. It must
|
|
76
|
+
# equal, byte for byte, a claim return URL your organization
|
|
77
|
+
# registered in EndPointBlank, or the call is refused with
|
|
78
|
+
# +return_to_not_registered+ (422).
|
|
73
79
|
# @return [Hash] <tt>{"client_id", "email", "sent_at", "expires_at"}</tt>
|
|
74
|
-
def claim_invite(client_id, email:, idempotency_key: nil)
|
|
75
|
-
|
|
80
|
+
def claim_invite(client_id, email:, return_to: nil, idempotency_key: nil)
|
|
81
|
+
body = { email: email }
|
|
82
|
+
body[:return_to] = return_to unless return_to.nil?
|
|
83
|
+
post_data(path("clients", client_id, "claim_invites"), body, idempotency_key)
|
|
76
84
|
end
|
|
77
85
|
end
|
|
78
86
|
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
module EndPointBlank
|
|
2
2
|
module Rack
|
|
3
3
|
module Headers
|
|
4
|
+
# Headers the SDK never sends to intake, lower-cased and matched in any
|
|
5
|
+
# letter case (sc-1470).
|
|
6
|
+
#
|
|
7
|
+
# A request record used to carry every inbound header, so a caller's
|
|
8
|
+
# `Authorization: Basic client_id:secret` or bearer token, a proxy
|
|
9
|
+
# credential and its session cookie landed in the provider's request log
|
|
10
|
+
# unless the provider had written a masking rule for them. The writers
|
|
11
|
+
# drop these before masking runs, rather than mask them, so no rule and
|
|
12
|
+
# no mask_hook can bring them back. `Set-Cookie` never arrives on a
|
|
13
|
+
# request; it is listed so a response record can never carry it either.
|
|
14
|
+
SENSITIVE_HEADERS = %w[authorization proxy-authorization cookie set-cookie].freeze
|
|
15
|
+
|
|
4
16
|
def self.extract
|
|
5
17
|
env = ::EndPointBlank::Rack::EnvStore.get
|
|
6
18
|
return {} if env.nil?
|
|
@@ -8,6 +20,20 @@ module EndPointBlank
|
|
|
8
20
|
env.select { |k,v| k.start_with? 'HTTP_'}.
|
|
9
21
|
transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') }
|
|
10
22
|
end
|
|
23
|
+
|
|
24
|
+
# The request's headers as a request or response record may send them:
|
|
25
|
+
# {extract} without any of {SENSITIVE_HEADERS}.
|
|
26
|
+
def self.reportable
|
|
27
|
+
without_sensitive(extract)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# A new hash of `headers` without any of {SENSITIVE_HEADERS}, whatever
|
|
31
|
+
# their letter case. Never changes its argument; nil is {}.
|
|
32
|
+
def self.without_sensitive(headers)
|
|
33
|
+
return {} if headers.nil?
|
|
34
|
+
|
|
35
|
+
headers.reject { |name, _value| SENSITIVE_HEADERS.include?(name.to_s.downcase) }
|
|
36
|
+
end
|
|
11
37
|
end
|
|
12
38
|
end
|
|
13
|
-
end
|
|
39
|
+
end
|
|
@@ -25,7 +25,9 @@ module EndPointBlank
|
|
|
25
25
|
env = ::EndPointBlank::Rack::EnvStore.get
|
|
26
26
|
request = ::Rack::Request.new(env)
|
|
27
27
|
version = Commands::VersionFinder.new.find(request)
|
|
28
|
-
|
|
28
|
+
# Authorization, Proxy-Authorization and Cookie are never sent,
|
|
29
|
+
# masking rule or not (Headers::SENSITIVE_HEADERS, sc-1470).
|
|
30
|
+
headers = ::EndPointBlank::Rack::Headers.reportable
|
|
29
31
|
|
|
30
32
|
{
|
|
31
33
|
app_name: EndPointBlank::Configuration.instance.app_name,
|
|
@@ -24,7 +24,10 @@ module EndPointBlank
|
|
|
24
24
|
def payload(status:, headers:, body:, data: {})
|
|
25
25
|
request = ::EndPointBlank::Rack::EnvStore.request
|
|
26
26
|
env = ::EndPointBlank::Rack::EnvStore.get
|
|
27
|
-
headers
|
|
27
|
+
# The record carries the request's headers, not the `headers:`
|
|
28
|
+
# argument, so without the sc-1470 filter a caller's Authorization
|
|
29
|
+
# and Cookie reached the response record too.
|
|
30
|
+
headers = ::EndPointBlank::Rack::Headers.reportable
|
|
28
31
|
version = request ? Commands::VersionFinder.new.find(request) : nil
|
|
29
32
|
route = request ? Commands::RoutePatternFinder.find(request) : nil
|
|
30
33
|
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: end_point_blank
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.13.
|
|
4
|
+
version: 0.13.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert A. Lasch
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-06 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: excon
|