diff --git a/preview/preview-stub-empty.js b/preview/preview-stub-empty.js new file mode 100644 index 0000000..157194c --- /dev/null +++ b/preview/preview-stub-empty.js @@ -0,0 +1,46 @@ +// Preview-only stub for the chrome.* extension API with realistic sample data. +// Loaded before the real popup.js / results.js in preview/*.html files. +// NOT shipped — build.sh only copies the explicit SHARED_FILES list. +(function () { + const NOW = Date.now(); + const MIN = 60 * 1000; + const HOUR = 60 * MIN; + const DAY = 24 * HOUR; + + const SAMPLE_FINDINGS = [ + { id: "f1", severity: "critical", provider: "AWS", patternName: "AWS Access Key ID", match: "AKIAIOSFODNN7EXAMPLE", type: "inline-script", domain: "dashboard.acme.io", url: "https://dashboard.acme.io/assets/app.js", pageUrl: "https://dashboard.acme.io/", timestamp: NOW - 4 * MIN }, + { id: "f2", severity: "critical", provider: "Stripe", patternName: "Stripe Live Secret Key", match: "sk_live_4eC39HqLyj…T1zdp7dc", type: "network-response", domain: "api.shopfront.dev", url: "https://api.shopfront.dev/v2/config", pageUrl: "https://shopfront.dev/", timestamp: NOW - 26 * MIN }, + { id: "f3", severity: "critical", provider: "OpenAI", patternName: "OpenAI API Key", match: "sk-proj-abc123def456ghi789jkl", type: "web-storage", domain: "playground.internal.tools", url: "https://playground.internal.tools/", pageUrl: "https://playground.internal.tools/", timestamp: NOW - 2 * HOUR }, + { id: "f4", severity: "high", provider: "GitHub", patternName: "GitHub Personal Access Token", match: "ghp_16C7e42F292c6912E7710c838347Ae178B4a", type: "html-comment", domain: "gitmirror.example.org", url: "https://gitmirror.example.org/login", pageUrl: "https://gitmirror.example.org/", timestamp: NOW - 3 * HOUR }, + { id: "f5", severity: "high", provider: "Slack", patternName: "Slack Bot Token", match: "xoxb-17653672481-19874698323-pdLjLl…CwXgE", type: "inline-script", domain: "status.teamchat.app", url: "https://status.teamchat.app/embed.js", pageUrl: "https://status.teamchat.app/", timestamp: NOW - 5 * HOUR }, + { id: "f6", severity: "high", provider: "MongoDB", patternName: "MongoDB Connection String", match: "mongodb+srv://admin:p4ssw0rd@cluster0.mongodb.net/prod", type: "data-attribute", domain: "metrics.saasly.co", url: "https://metrics.saasly.co/", pageUrl: "https://metrics.saasly.co/", timestamp: NOW - 9 * HOUR }, + { id: "f7", severity: "high", provider: "DOM Scan", patternName: "Sensitive Meta Tag", match: "csrf-token=9f8e7d6c5b4a3210", type: "meta-tag", domain: "legacy.corpnet.com", url: "https://legacy.corpnet.com/index.html", pageUrl: "https://legacy.corpnet.com/", timestamp: NOW - 14 * HOUR }, + { id: "f8", severity: "medium", provider: "Generic", patternName: "JSON Web Token (JWT)", match: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U", type: "url-param", domain: "auth.redirectlab.net", url: "https://auth.redirectlab.net/callback?token=eyJhbGciOi...", pageUrl: "https://redirectlab.net/", timestamp: NOW - 20 * HOUR }, + { id: "f9", severity: "medium", provider: "DOM Scan", patternName: "Hidden Form Field", match: "session_id=a8f5f167f44f4964e6c998dee827110c", type: "hidden-input", domain: "shop.example.com", url: "https://shop.example.com/checkout", pageUrl: "https://shop.example.com/", timestamp: NOW - 1 * DAY }, + { id: "f10", severity: "medium", provider: "URL Scan", patternName: "High-Entropy URL Parameter", match: "sig=4c4f6e6f2d9a4b8c8d7e6f5a4b3c2d1e", type: "url-param", domain: "cdn.medialab.io", url: "https://cdn.medialab.io/v/assets?sig=4c4f6e...", pageUrl: "https://medialab.io/", timestamp: NOW - 2 * DAY }, + { id: "f11", severity: "medium", provider: "Web Storage", patternName: "localStorage Secret", match: "refresh_token=def502001a2b3c4d5e6f", type: "web-storage", domain: "app.notesync.dev", url: "https://app.notesync.dev/", pageUrl: "https://app.notesync.dev/", timestamp: NOW - 3 * DAY }, + { id: "f12", severity: "low", provider: "Generic", patternName: "Keyword: client_id", match: "client_id=Iv1.8a61f9b3a7aba766", type: "script-src", domain: "login.oauthflow.app", url: "https://login.oauthflow.app/js/oauth.js?client_id=Iv1.8a61f9b3a7aba766", pageUrl: "https://login.oauthflow.app/", timestamp: NOW - 4 * DAY }, + ]; + + const SAMPLE_KEYWORDS = [ + "key", "api_key", "apikey", "api-key", "secret", "token", + "access_token", "auth", "credential", "password", "client_id", "client_secret", + ]; + + window.chrome = { + runtime: { + getManifest: () => ({ version: "2.2.0" }), + sendMessage: async (msg) => { + switch (msg && msg.type) { + case "getFindings": return { findings: [] }; + case "getKeywords": return { keywords: SAMPLE_KEYWORDS.slice() }; + case "addKeyword": return { ok: true }; + case "removeKeyword": return { ok: true }; + case "removeFinding": return { ok: true }; + case "clearFindings": return { ok: true }; + default: return {}; + } + }, + }, + }; +})(); diff --git a/preview/preview-stub.js b/preview/preview-stub.js index b8e17d2..8440831 100644 --- a/preview/preview-stub.js +++ b/preview/preview-stub.js @@ -29,7 +29,7 @@ window.chrome = { runtime: { - getManifest: () => ({ version: "2.1.1" }), + getManifest: () => ({ version: "2.2.0" }), sendMessage: async (msg) => { switch (msg && msg.type) { case "getFindings": return { findings: SAMPLE_FINDINGS.slice() }; diff --git a/preview/results-preview-empty.html b/preview/results-preview-empty.html new file mode 100644 index 0000000..55d32ad --- /dev/null +++ b/preview/results-preview-empty.html @@ -0,0 +1,122 @@ + + + + + + KeyFinder — Findings Console + + + +
+
+
+ +
+

KEYFINDER

+

findings console

+
+ PASSIVE +
+
+
+ + + / +
+
+ + + +
+
+
+
+
+ + + +
+
+
+
+ +
+ + + +
+
+
+ findings.log + +
+ + + + + + + + + + + + + + + + +
#SeverityProviderPatternMatchTypeDomainSourceTime
+ +
+ +
+ + + + + diff --git a/preview/store-popup.html b/preview/store-popup.html new file mode 100644 index 0000000..24cd9fb --- /dev/null +++ b/preview/store-popup.html @@ -0,0 +1,78 @@ + + + + + KeyFinder — store shot (popup) + + + + +
+
+
KEYFINDER v2.2.0 — PASSIVE SCANNER
+

Catch leaked keys
while you browse.

+

KeyFinder passively scans every page for exposed API keys, tokens and credentials — across scripts, DOM, storage and network responses.

+ +
+ +
+ + + + diff --git a/preview/store.css b/preview/store.css new file mode 100644 index 0000000..d15052d --- /dev/null +++ b/preview/store.css @@ -0,0 +1,120 @@ +/* Store-listing composition backdrop (preview only, not shipped) */ + +body.store { + width: auto; + min-width: 0; + background: #04060a; + overflow: hidden; +} + +.stage { + position: relative; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 72px; + width: 1280px; + height: 800px; + padding: 0 64px; +} + +/* ambient brand glows */ +.stage::before { + content: ""; + position: absolute; + inset: 0; + background: + radial-gradient(560px 420px at 12% 18%, rgba(245,165,36,.09) 0%, transparent 60%), + radial-gradient(620px 480px at 88% 82%, rgba(69,208,196,.07) 0%, transparent 60%); + pointer-events: none; +} + +.copy { max-width: 560px; } + +.kicker { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 10px; + font-weight: 700; + letter-spacing: .22em; + color: var(--green); + border: 1px solid rgba(61,220,151,.32); + background: rgba(61,220,151,.06); + padding: 5px 9px; + border-radius: 2px; + margin-bottom: 26px; +} +.kicker::before { + content: ""; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--green); + box-shadow: 0 0 8px var(--green); +} + +.copy h1 { + font-size: 46px; + font-weight: 700; + line-height: 1.08; + letter-spacing: .01em; + color: #fff; + margin-bottom: 20px; +} +.copy h1 em { + font-style: normal; + color: var(--amber); +} + +.copy p { + font-size: 13px; + line-height: 1.7; + color: var(--text-dim); + margin-bottom: 26px; + max-width: 440px; +} + +.spec { + list-style: none; + display: flex; + flex-direction: column; + gap: 9px; +} +.spec li { + display: flex; + align-items: center; + gap: 10px; + font-size: 11px; + letter-spacing: .08em; + color: var(--text-faint); + text-transform: uppercase; +} +.spec li::before { + content: "▸"; + color: var(--teal); + font-size: 10px; +} + +/* floating popup frame */ +.popup-frame { + position: relative; + flex: none; + width: 372px; + border: 1px solid var(--line-strong); + border-radius: 8px; + overflow: hidden; + box-shadow: + 0 0 0 1px rgba(245,165,36,.08), + 0 24px 80px rgba(0,0,0,.65), + 0 0 120px rgba(245,165,36,.05); +} +.popup-frame::before { + content: ""; + position: absolute; + top: 0; left: 0; right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(245,165,36,.6), transparent); + z-index: 2; +} diff --git a/store/store-1-dashboard.png b/store/store-1-dashboard.png new file mode 100644 index 0000000..df6b482 Binary files /dev/null and b/store/store-1-dashboard.png differ diff --git a/store/store-2-popup.png b/store/store-2-popup.png new file mode 100644 index 0000000..29e2df0 Binary files /dev/null and b/store/store-2-popup.png differ diff --git a/store/store-3-empty.png b/store/store-3-empty.png new file mode 100644 index 0000000..35c3d22 Binary files /dev/null and b/store/store-3-empty.png differ