zeroclick-sellers 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27bd4f5d8f10f026b12a89ee8681fef45ffbf58129df180f40903a55ec9743d3
4
- data.tar.gz: 1ea73b94f08215d28c2974ac4937bdc423aa2f52a66c688a5746656ad837c8f2
3
+ metadata.gz: 2865ea4c52917887161bb00e22f46bdd275f28a6a7ac3a2e72d680b3db32323c
4
+ data.tar.gz: 4ca1a1c4665a099a54e15fb459a36eaa951feb718331fa6303cd4e81b2356d22
5
5
  SHA512:
6
- metadata.gz: 73ef4fc05515a9d11212ca90c7df1c9f97c157bdc2628c4b1bb81738849552fbd7aca334986fc60f1c4d0d5cb6ca311b7663c453c1633a756950e82af4f06b42
7
- data.tar.gz: 00dbf768601b7808759518ad6a507e0d238f4c6c65aecdd91ce5106488841a19538f5ea49ea5df93e776a049330f32f834d7d9216dd0ce58b212bf6da24e1748
6
+ metadata.gz: 1b9b122f2cea8b056f79fe2aa56af4d674818148ae8e6b60adb4ac9b000520f06d360c22980c0c6900e87bc02882218d1e9e4815248b8d65d5319608e1a4d0a4
7
+ data.tar.gz: 81c0463cda57c90787550a9215a786d41d555486eaef5af19f081b965af84608d87819f2f053be1195425e815aa985d777761897090049bbced8dcb74981e73c
@@ -22,6 +22,9 @@ module ZeroClick
22
22
  # - the app runs FIRST, so the beacon carries the real status and
23
23
  # duration; the visitor's user-agent, accept, and connecting IP are
24
24
  # forwarded for server-side classification;
25
+ # - the visitor's country rides along when the edge resolved it: the
26
+ # header Cloudflare, CloudFront, Vercel or App Engine sets, or
27
+ # +resolve_country+; a host whose edge sets none sends no country;
25
28
  # - a ZeroClick agent-eval request's tag and signature are forwarded
26
29
  # with the page's host, so the API can keep ZeroClick's own eval
27
30
  # traffic out of the seller's numbers; a browser-based run, which
@@ -55,6 +58,20 @@ module ZeroClick
55
58
  # the whole visit out of the seller's numbers from it.
56
59
  EVAL_SOURCE_PREFIX = "ze-"
57
60
 
61
+ # The vendor request headers (as Rack env keys) that carry the
62
+ # visitor's country as the edge resolved it, outermost layer first: a
63
+ # CDN in front of a platform sees the true client, while the platform
64
+ # behind it geolocates the CDN's edge, so the outer header wins when
65
+ # both are present. Each is the vendor's documented header, forwarded
66
+ # raw; the API clamps it to a 2-letter code and drops the vendors'
67
+ # unknown sentinels (Cloudflare XX, App Engine ZZ).
68
+ COUNTRY_HEADERS = %w[
69
+ HTTP_CF_IPCOUNTRY
70
+ HTTP_CLOUDFRONT_VIEWER_COUNTRY
71
+ HTTP_X_VERCEL_IP_COUNTRY
72
+ HTTP_X_APPENGINE_COUNTRY
73
+ ].freeze
74
+
58
75
  # +seller+ may be a client, a callable returning one, or omitted to
59
76
  # resolve the process-wide ZeroClick::Sellers.seller on the first
60
77
  # request (the Rails path — see Base#initialize for why).
@@ -65,14 +82,19 @@ module ZeroClick
65
82
  # public URL of the request, for servers behind a proxy that rewrites
66
83
  # the host the runtime sees; its path is reported and, with an eval
67
84
  # tag, its host. +on_error+ observes the fire-and-forget
68
- # path; it is never re-raised.
69
- def initialize(app, seller_id:, seller: nil, clock: nil, resolve_url: nil, on_error: nil)
85
+ # path; it is never re-raised. +resolve_country+ is a callable taking
86
+ # the Rack env and returning the visitor's country, replacing the
87
+ # vendor-header read (COUNTRY_HEADERS) with the seller's own source:
88
+ # exactly one header, or a runtime that exposes the country another
89
+ # way. Return nil for unknown.
90
+ def initialize(app, seller_id:, seller: nil, clock: nil, resolve_url: nil, on_error: nil, resolve_country: nil)
70
91
  @app = app
71
92
  @seller_source = seller
72
93
  @seller_id = seller_id
73
94
  @clock = clock || DEFAULT_CLOCK
74
95
  @resolve_url = resolve_url
75
96
  @on_error = on_error
97
+ @resolve_country = resolve_country
76
98
  end
77
99
 
78
100
  def call(env)
@@ -114,7 +136,7 @@ module ZeroClick
114
136
  user_agent: env["HTTP_USER_AGENT"],
115
137
  accept: env["HTTP_ACCEPT"],
116
138
  client_ip: client_ip_of(env),
117
- country: env["HTTP_CF_IPCOUNTRY"],
139
+ country: country_of(env),
118
140
  referrer_host: referrer_host_of(env),
119
141
  journey_id: journey_id_of(headers),
120
142
  **start_marker_of(uri),
@@ -205,6 +227,20 @@ module ZeroClick
205
227
  first.empty? ? nil : first
206
228
  end
207
229
 
230
+ # The visitor's country as the edge resolved it: the first present of
231
+ # COUNTRY_HEADERS, or whatever +resolve_country+ returns. nil when the
232
+ # edge set none of them, so a host without one sends no country rather
233
+ # than a guess; an empty value is left out the same way.
234
+ def country_of(env)
235
+ value = if @resolve_country
236
+ @resolve_country.call(env)
237
+ else
238
+ COUNTRY_HEADERS.lazy.map { |key| env[key] }.find { |v| v && !v.strip.empty? }
239
+ end
240
+ value = value&.strip
241
+ value.nil? || value.empty? ? nil : value
242
+ end
243
+
208
244
  # The referrer reduced to its host at the edge, so the full referrer
209
245
  # (its path and query, which can carry identifying values) never leaves
210
246
  # the site. A malformed referrer yields no host rather than the full URL.
@@ -4,6 +4,6 @@ module ZeroClick
4
4
  module Sellers
5
5
  # Bump this to publish. The workflow reads it, asks RubyGems whether this
6
6
  # version already exists, and publishes only when it does not.
7
- VERSION = "0.7.0"
7
+ VERSION = "0.8.0"
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zeroclick-sellers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ZeroClick
@@ -15,7 +15,7 @@ description: |
15
15
  and report what was used. Ships Rack middleware, so it works in Rails,
16
16
  Sinatra, Hanami and Roda alike.
17
17
  email:
18
- - support@zeroclick.ai
18
+ - help@zeroclick.ai
19
19
  executables: []
20
20
  extensions: []
21
21
  extra_rdoc_files: []