Skip to content

Sanitize affiliate tracking code prefixes#463

Merged
ralyodio merged 1 commit into
profullstack:masterfrom
rissrice2105-agent:codex/affiliate-tracking-code-slug
Jun 14, 2026
Merged

Sanitize affiliate tracking code prefixes#463
ralyodio merged 1 commit into
profullstack:masterfrom
rissrice2105-agent:codex/affiliate-tracking-code-slug

Conversation

@rissrice2105-agent

Copy link
Copy Markdown
Contributor

Closes #462.

Summary

  • Normalize the username prefix used by generateTrackingCode() to URL-safe lowercase slug characters.
  • Add an affiliate fallback when a username has no safe characters.
  • Add regression coverage for usernames containing spaces/symbols and fallback-only values.

Verification

  • corepack pnpm vitest run src/lib/affiliates/tracking.test.ts
  • corepack pnpm tsc --noEmit

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR sanitizes the username prefix in generateTrackingCode() to produce URL-safe, lowercase slug characters, and adds an "affiliate" fallback for usernames that contain no safe characters.

  • tracking.ts: Inserts a four-step normalization pipeline (lowercase → replace non-alphanumeric with - → trim edge dashes → truncate to 48 chars → fallback to "affiliate") between the raw username and the returned tracking code.
  • tracking.test.ts: Adds two regression tests — one covering mixed spaces/symbols ("Alice Smith/@Example") and one covering the all-invalid-characters fallback ("!!!").

Confidence Score: 4/5

Safe to merge — the sanitization is isolated to new code generation and does not affect existing stored tracking codes or any lookup paths.

The change is small and well-targeted. Existing tracking codes in the database are unaffected because they are looked up by exact stored value. The one thing worth a second look is the ordering of the dash-trim and the slice: trimming before slicing means a username whose 48th character lands inside a hyphen-run will produce a prefix ending in a dash, giving a double-dash in the final code. This is cosmetic rather than functional, but adding a second trim after the slice would close it completely.

Only tracking.ts warrants a close look — specifically the order of .replace(/^-+|-+$/g, "") relative to .slice(0, 48).

Important Files Changed

Filename Overview
src/lib/affiliates/tracking.ts Adds sanitization pipeline (lowercase → slug → trim → truncate → fallback) for the username prefix in generateTrackingCode. Minor: trim runs before slice, so a slice at a dash boundary can leave a trailing hyphen in the prefix.
src/lib/affiliates/tracking.test.ts Adds two targeted regression tests for the new sanitization: one for mixed special characters/spaces and one for the all-invalid-characters fallback. Existing tests are unaffected.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["generateTrackingCode(username, offerSlug)"] --> B["base = username + '-' + offerSlug\n(unchanged, used for hash seed)"]
    A --> C["username.toLowerCase()"]
    C --> D["replace([^a-z0-9]+ → '-')"]
    D --> E["trim leading/trailing dashes"]
    E --> F["slice(0, 48)"]
    F --> G{result empty?}
    G -- yes --> H["prefix = 'affiliate'"]
    G -- no --> I["prefix = sanitized string"]
    H --> J["hash = SHA256(base + Date.now()).slice(0,6)"]
    I --> J
    B --> J
    J --> K["return prefix + '-' + hash"]
Loading

Reviews (1): Last reviewed commit: "Sanitize affiliate tracking code prefixe..." | Re-trigger Greptile

Comment on lines +22 to +26
const prefix = username
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 48) || "affiliate";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Trailing dash possible after slice

The dash-trim (.replace(/^-+|-+$/g, "")) runs before .slice(0, 48), so if the slice boundary falls on a hyphen the prefix can end with -, producing a double-dash in the final tracking code (e.g. aaaa...a--abc123). A username like "a" * 47 + " extra" sanitizes to "a"*47 + "-extra" and slices to "a"*47 + "-", yielding the prefix aaaa...a-. Apply the trim a second time after slicing to prevent this.

@@ -19,12 +19,17 @@ async function getAttributionWindowStart(admin: SupabaseClient, offerId: string)
*/
export function generateTrackingCode(username: string, offerSlug: string): string {
const base = `${username}-${offerSlug}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Hash seed uses original unsanitized username

The base variable (used as the hash seed) still embeds the raw username, but the prefix returned in the tracking code is now the sanitized form. This means the human-readable portion of the code (prefix) no longer matches the entropy source (base). For usernames that sanitize to "affiliate" (the fallback), all such usernames share the same prefix but generate hashes from their distinct raw values — so codes are still unique. The disconnect is harmless today, but if base were ever used to reverse-lookup or validate the prefix this divergence would be surprising. Consider using prefix (or a normalized form) as the base instead of the raw username.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@rissrice2105-agent

Copy link
Copy Markdown
Contributor Author

CI is green for PR #463.

Verification:

  • corepack pnpm vitest run src/lib/affiliates/tracking.test.ts
  • corepack pnpm tsc --noEmit

uGig invoice evidence has been sent for this PR.

@ralyodio ralyodio merged commit 1d5b582 into profullstack:master Jun 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Affiliate tracking codes can include unsafe username characters

2 participants