@goodandready/dsh-usage-guard 0.1.15 → 0.1.16

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.
package/lib/index.js CHANGED
@@ -156,8 +156,6 @@ export function apply(ctx, config) {
156
156
  badFields: bad,
157
157
  fixedTokenCount: fixedTokensCount,
158
158
  clamped: clampedAny,
159
- provider: event?.provider ?? event?.data?.provider ?? 'unknown',
160
- sample: found.usage,
161
159
  })
162
160
 
163
161
  if (live && live.report !== false) {
package/lib/telemetry.js CHANGED
@@ -11,7 +11,7 @@ class UsageGuardTelemetry {
11
11
  this.recentIncidents = [];
12
12
  }
13
13
 
14
- recordIncident({ turn = 0, step = 0, badFields = [], fixedTokenCount = 0, clamped = false, provider = 'unknown', sample = null, kind = 'malformed-usage', target = '' } = {}) {
14
+ recordIncident({ turn = 0, step = 0, badFields = [], fixedTokenCount = 0, clamped = false, kind = 'malformed-usage', target = '' } = {}) {
15
15
  this.rescuedEvents += 1;
16
16
  this.fixedTokens += Number(fixedTokenCount) || 0;
17
17
  if (clamped) {
@@ -26,8 +26,6 @@ class UsageGuardTelemetry {
26
26
  target: String(target || (Array.isArray(badFields) ? badFields.join(',') : '')),
27
27
  fields: Array.isArray(badFields) ? badFields : [],
28
28
  clamped: Boolean(clamped),
29
- provider: typeof provider === 'string' ? provider : 'unknown',
30
- sample: sample && typeof sample === 'object' ? JSON.stringify(sample).slice(0, 300) : null,
31
29
  };
32
30
 
33
31
  this.lastIncident = incident;
@@ -89,6 +87,100 @@ export function resetTelemetry() {
89
87
  telemetry.reset();
90
88
  }
91
89
 
90
+ function header(request, name) {
91
+ const value = request?.headers?.[name.toLowerCase()];
92
+ return Array.isArray(value) ? value[0] : value;
93
+ }
94
+
95
+ function isLoopbackAddress(value) {
96
+ const address = String(value || '').toLowerCase().replace(/^[[\]]/g, '');
97
+ return address === 'localhost' || address === 'localhost.' || address === '::1'
98
+ || address.startsWith('127.')
99
+ || address.startsWith('::ffff:127.');
100
+ }
101
+
102
+ /** Reject cross-site and unauthenticated requests while allowing same-origin and local callers. */
103
+ export function isTrustedSettingsRequest(request, options = {}) {
104
+ if (!request || typeof request !== 'object' || !request.headers) return false;
105
+
106
+ const secFetchSite = header(request, 'sec-fetch-site');
107
+ // Unconditionally reject cross-site requests
108
+ if (secFetchSite === 'cross-site') {
109
+ return false;
110
+ }
111
+
112
+ const host = header(request, 'x-forwarded-host') || header(request, 'host');
113
+ const origin = header(request, 'origin');
114
+ if (origin) {
115
+ try {
116
+ const url = new URL(origin);
117
+ if (host && url.host.toLowerCase() === host.toLowerCase()) {
118
+ return true;
119
+ }
120
+ if (isLoopbackAddress(url.hostname) && isLoopbackAddress(request?.socket?.remoteAddress)) {
121
+ return true;
122
+ }
123
+ return false;
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+
129
+ const referer = header(request, 'referer');
130
+ if (referer) {
131
+ try {
132
+ const url = new URL(referer);
133
+ if (host && url.host.toLowerCase() === host.toLowerCase()) {
134
+ return true;
135
+ }
136
+ if (isLoopbackAddress(url.hostname) && isLoopbackAddress(request?.socket?.remoteAddress)) {
137
+ return true;
138
+ }
139
+ return false;
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+
145
+ // Check Bearer token or custom auth header
146
+ const expectedToken = options.expectedToken
147
+ || (typeof process !== 'undefined' ? (process.env?.DSH_AUTH_TOKEN || process.env?.DSH_TOKEN) : null);
148
+
149
+ const auth = header(request, 'authorization');
150
+ if (typeof auth === 'string' && auth.startsWith('Bearer ')) {
151
+ const bearer = auth.slice(7).trim();
152
+ if (expectedToken && bearer && bearer === expectedToken) {
153
+ return true;
154
+ }
155
+ }
156
+
157
+ const customAuth = header(request, 'x-dsh-auth');
158
+ if (expectedToken && customAuth && customAuth === expectedToken) {
159
+ return true;
160
+ }
161
+
162
+ // Check cookie authentication
163
+ const cookie = header(request, 'cookie');
164
+ if (typeof cookie === 'string' && expectedToken) {
165
+ const match = cookie.match(/(?:^|;\s*)(?:token|dsh-auth|dsh_token)=([^;]+)/);
166
+ if (match && match[1] === expectedToken) {
167
+ return true;
168
+ }
169
+ }
170
+
171
+ // Same-origin or same-site fetch
172
+ if (secFetchSite === 'same-origin' || secFetchSite === 'same-site') {
173
+ return true;
174
+ }
175
+
176
+ // Loopback connection (curl, local process)
177
+ if (isLoopbackAddress(request?.socket?.remoteAddress)) {
178
+ return true;
179
+ }
180
+
181
+ return false;
182
+ }
183
+
92
184
  export function registerTelemetryRoute(ctx, options = {}) {
93
185
  const endpoint = options.endpoint || '/api/dsh-usage-guard/telemetry';
94
186
  return ctx.webServer.register({
@@ -100,6 +192,14 @@ export function registerTelemetryRoute(ctx, options = {}) {
100
192
  response.end();
101
193
  return;
102
194
  }
195
+ if (!isTrustedSettingsRequest(request, options)) {
196
+ response.writeHead(403, {
197
+ 'content-type': 'application/json; charset=utf-8',
198
+ 'cache-control': 'no-store',
199
+ });
200
+ response.end(request.method === 'HEAD' ? undefined : JSON.stringify({ error: 'Forbidden: untrusted or cross-site request' }));
201
+ return;
202
+ }
103
203
  const snapshot = telemetry.getSnapshot();
104
204
  response.writeHead(200, {
105
205
  'content-type': 'application/json; charset=utf-8',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-usage-guard",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Keeps a malformed token-usage sample from taking a whole session history down with it: a missing or non-numeric counter becomes zero before the harness adds it up, so the fold never yields NaN and already-broken sessions open again.",
5
5
  "keywords": [
6
6
  "deepseek-harness",