Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions log-collector/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.wrangler
.dev.vars
15 changes: 15 additions & 0 deletions log-collector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "log-collector",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "wrangler dev",
"deploy": "wrangler deploy",
"cf-typegen": "wrangler types"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250124.0",
"typescript": "^5.5.2",
"wrangler": "^3.101.0"
}
}
49 changes: 49 additions & 0 deletions log-collector/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export interface Env {
PROFOUND_API_URL: string;
PROFOUND_API_KEY: string;
}

export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const response = await fetch(request);
const responseClone = response.clone();

ctx.waitUntil(handleRequest(request, responseClone, env));
return response;
}
} satisfies ExportedHandler<Env>;

async function handleRequest(request: Request, response: Response, env: Env) {
const requestUrl = new URL(request.url);

const headerSize = Array.from(response.headers.entries()).reduce(
(total, [key, value]) => total + key.length + value.length + 4,
0
);

const responseBody = await response.blob();
const bodySize = responseBody.size;
const totalBytesSent = headerSize + bodySize;

const logData = {
timestamp: Date.now(),
host: requestUrl.hostname,
method: request.method,
pathname: requestUrl.pathname,
query_params: Object.fromEntries(requestUrl.searchParams),
ip: request.headers.get('cf-connecting-ip'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Verify compliance with privacy regulations before logging client IP addresses.

Logging cf-connecting-ip (client IP address) to a third-party analytics service constitutes processing of personal data under GDPR/CCPA. Ensure:

  1. This data collection is disclosed in the privacy policy
  2. Appropriate data processing agreements are in place with Profound
  3. Consider whether IP anonymization/hashing would suffice for your analytics needs
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@log-collector/src/index.ts` at line 34, The code reads the client IP via
request.headers.get('cf-connecting-ip') and sends it to Profound, which may
process personal data; before keeping this, ensure privacy compliance by (1)
adding disclosure in the privacy policy about collecting IPs, (2) establishing a
Data Processing Agreement with Profound, and (3) implementing a safer default in
the log pipeline: replace the direct use of
request.headers.get('cf-connecting-ip') with an anonymized/hashed value (or drop
the field) and gate sending via a configurable consent/feature flag so IPs are
only included when legal bases and agreements are in place.

userAgent: request.headers.get('user-agent'),
referer: request.headers.get('referer'),
bytes: totalBytesSent,
status: response.status
};

await fetch(env.PROFOUND_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': env.PROFOUND_API_KEY
},
body: JSON.stringify([logData])
}).catch((error) => console.error('Failed to send logs:', error));
}
14 changes: 14 additions & 0 deletions log-collector/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ESNext"],
"types": ["@cloudflare/workers-types/2023-07-01"],
"noEmit": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
16 changes: 16 additions & 0 deletions log-collector/wrangler.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "log-collector",
"main": "src/index.ts",
"compatibility_date": "2025-01-29",
"observability": {
"enabled": true
},
"route": {
"pattern": "appwrite.io/*",
"zone_name": "appwrite.io"
},
"vars": {
"PROFOUND_API_URL": "https://artemis.api.tryprofound.com/v1/logs/cloudflare_worker"
}
}