diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 17849ab..3ede3d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -167,4 +167,4 @@ If you have questions, please open an issue on GitHub. ## License -By contributing, you agree that your contributions will be licensed under the MIT License. +By contributing, you agree that your contributions will be licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). diff --git a/RAPIDAPI.md b/RAPIDAPI.md index 436aec7..2d0e2eb 100644 --- a/RAPIDAPI.md +++ b/RAPIDAPI.md @@ -11,7 +11,7 @@ - **Flexible Redaction**: Choose between masking (`***`) or placeholders (``). - **Entity Filtering**: Select exactly which PII types to redact. - **Multi-Language**: Optimized for English and Russian. -- **High Performance**: < 20ms response time for typical payloads. +- **Detection Methods**: Regex patterns for email, phone, and card candidates; spaCy NER for person names. --- @@ -19,10 +19,10 @@ | Type | Description | Detection Method | |------|-------------|------------------| -| `EMAIL` | Email addresses | Regex (100% accuracy) | -| `PHONE` | International phone numbers | Regex (100% accuracy) | -| `CARD` | Credit/debit card numbers | Regex + Luhn check | -| `PERSON` | Person names | AI/NER (spaCy) | +| `EMAIL` | Email addresses | Regex | +| `PHONE` | International phone numbers | Regex | +| `CARD` | Credit/debit card number candidates | Regex | +| `PERSON` | Person names | spaCy NER | --- diff --git a/RAPIDAPI_LISTING.md b/RAPIDAPI_LISTING.md index fd9c8f1..e34a288 100644 --- a/RAPIDAPI_LISTING.md +++ b/RAPIDAPI_LISTING.md @@ -9,8 +9,7 @@ Every time you send customer data to a public LLM, you risk a leak. Names, email ### Why Masker? * **0% Retention:** We are stateless. Your data is processed in RAM and forgotten instantly. -* **High Velocity:** Built for high-throughput pipelines. <50ms latency P95. -* **Context Aware:** Unlike regex, our NER models understand context, distinguishing between a dollar amount and a credit card number. +* **Detection Methods:** Regex patterns handle email, phone, and card candidates; spaCy NER handles person-name candidates. ### Core Features * **Smart Redaction:** Replace PII with tokenized placeholders (e.g., `[EMAIL]`, `[PERSON]`) so LLMs can still understand the sentence structure. @@ -35,7 +34,7 @@ You may not use the Service to: The Service is **stateless**. We process your input text solely for the purpose of redaction and do not store, log, or train on your payloads. Once the response is returned, your data is wiped from our memory. **3. Disclaimer of Warranty** -The Service is provided "AS IS". While we strive for high accuracy (>95% F1-score), no automated PII detection system is perfect. You remain largely responsible for ensuring your data compliance (GDPR, CCPA, HIPAA). We are not liable for any missed PII entities or subsequent data leaks. +The Service is provided "AS IS". No automated PII detection system is perfect. You remain largely responsible for ensuring your data compliance (GDPR, CCPA, HIPAA). We are not liable for any missed PII entities or subsequent data leaks. **4. Fair Use** We reserve the right to throttle or terminate API keys that exhibit abusive behavior, consistent errors, or attempts to bypass rate limits. diff --git a/RAPIDAPI_README.md b/RAPIDAPI_README.md index 22d78b1..137a53e 100644 --- a/RAPIDAPI_README.md +++ b/RAPIDAPI_README.md @@ -1,6 +1,6 @@ # Masker - The PII Redaction Firewall -Welcome to Masker. This guide will help you integrate high-performance PII redaction into your applications in minutes. +Welcome to Masker. This guide will help you integrate PII redaction into your applications. ## 🚀 Quick Start Masker is designed to be dead simple. You send text, we return purged text. @@ -98,8 +98,8 @@ Masker isn't just for flat text. You can send complex nested JSON objects, and w We automatically detect the following entities: * `EMAIL` - Email addresses * `PHONE` - International phone numbers -* `CARD` - Credit cards, debit cards (Luhn validated) -* `PERSON` - Person names (using Neural NER models) +* `CARD` - Credit and debit card number candidates detected with regex +* `PERSON` - Person-name candidates detected with spaCy NER You can restrict detection to specific types using the `entities` array: ```json @@ -111,9 +111,8 @@ You can restrict detection to specific types using the `entities` array: --- -## ⚡ Performance & Limits -* **Latency:** P95 < 50ms for typical inputs. -* **Batch Size:** Ensure payloads are < 5MB. +## ⚡ Limits +* **Payload Size:** Requests are validated against the service's configured text and payload limits. * **Concurrency:** Stateless architecture scales horozontally. Contact us for custom enterprise limits. ## 🔒 Security diff --git a/app/api/v1/detect.py b/app/api/v1/detect.py index 839b51c..9e9e857 100644 --- a/app/api/v1/detect.py +++ b/app/api/v1/detect.py @@ -49,10 +49,10 @@ ## Detected Entity Types -- **EMAIL**: Email addresses (regex, 100% accuracy) -- **PHONE**: Phone numbers (international formats, 100% accuracy) -- **CARD**: Credit card numbers (regex + Luhn validation, 100% accuracy) -- **PERSON**: Person names (spaCy NER, ~85% accuracy) +- **EMAIL**: Email addresses (regex) +- **PHONE**: Phone numbers (international formats, regex) +- **CARD**: Credit card number candidates (regex) +- **PERSON**: Person names (spaCy NER) ## Example Response diff --git a/demo/index.html b/demo/index.html index e4004e7..0f44f9c 100644 --- a/demo/index.html +++ b/demo/index.html @@ -3,7 +3,9 @@ - Masker API | Privacy for LLMs + + + Masker | Client-side PII masking preview @@ -20,18 +22,18 @@

Protect Your Data

-

Before It Reaches AI

+

Before It Reaches AI

- The ultimate PII redaction layer for LLMs. - Stateless. Fast. Secure. + Preview local regex masking for common identifiers before sharing text with AI tools. + This browser demo is not the full Masker API.

Try Live Demo @@ -58,7 +60,7 @@

Before It Reaches AI

- SYSTEM ACTIVE + CLIENT-SIDE PREVIEW
@@ -66,19 +68,19 @@

Before It Reaches AI

Interactive Console

-

Type anything. We'll find the secrets.

+

Paste text to preview regex masking for emails, phone numbers, and card-like numbers. Review the result before use.

-
masker_cli — v1.0.0
+
masker_regex_preview
> - +
@@ -95,18 +97,18 @@

Interactive Console

🔒
-

Privacy First

-

Stateless processing. No database. No logs. Your data never touches a disk.

+

Local Preview

+

Pasted text is processed by this page's client-side JavaScript and is not sent to the Masker API.

-

Ultra Fast

-

Optimized regex & lightweight NLP. Sub-20ms latency for real-time streams.

+

Three Regex Patterns

+

The preview highlights email addresses, phone numbers, and card-like 16-digit strings.

🌍
-

Multi-Language

-

Native support for English and Russian entity recognition out of the box.

+

Full API Source

+

Use the documentation to run the Python API locally and review its supported entities and deployment boundaries.

@@ -116,7 +118,7 @@

Multi-Language

diff --git a/demo/script.js b/demo/script.js index 6f3f88b..a6d0dea 100644 --- a/demo/script.js +++ b/demo/script.js @@ -39,13 +39,13 @@ gsap.from('.feature-card', { stagger: 0.2 }); -// Interactive Demo Logic (Client-side emulation for speed/demo purposes) +// Interactive Demo Logic (client-side regex preview, not the full Masker API) const demoInput = document.getElementById('demo-input'); const demoOutput = document.getElementById('demo-output'); const demoStats = document.getElementById('demo-stats'); const processingLine = document.querySelector('.processing-line'); -// Simple regex for demo purposes (Backend is much more powerful) +// This preview intentionally covers only these three regex patterns. const PATTERNS = { email: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, phone: /(\+\d{1,3}[-.\s]?)?(\(\d{1,4}\)[-.\s]?)?\d{3,4}[-.\s]?\d{3,4}/g, @@ -66,32 +66,29 @@ demoInput.addEventListener('input', () => { function processText(text) { if (!text) { - demoOutput.innerHTML = ''; - demoStats.innerHTML = ''; + demoOutput.replaceChildren(); + demoStats.replaceChildren(); processingLine.classList.add('hidden'); return; } const startTime = performance.now(); - let maskedText = text; - let count = 0; - - // Apply masking - maskedText = maskedText.replace(PATTERNS.email, () => { count++; return '***'; }); - maskedText = maskedText.replace(PATTERNS.phone, () => { count++; return '***'; }); - maskedText = maskedText.replace(PATTERNS.card, () => { count++; return '***'; }); + const ranges = findMaskRanges(text); const endTime = performance.now(); const duration = (endTime - startTime).toFixed(2); - demoOutput.innerHTML = maskedText; + renderMaskedText(text, ranges); demoOutput.style.opacity = '1'; processingLine.classList.add('hidden'); - demoStats.innerHTML = ` - ⚡ Processed in ${duration}ms - 🛡️ ${count} PII entities masked - `; + const durationStat = document.createElement('span'); + durationStat.textContent = `⚡ Regex pass in ${duration}ms`; + + const matchStat = document.createElement('span'); + matchStat.textContent = `🛡️ ${ranges.length} regex matches masked`; + + demoStats.replaceChildren(durationStat, matchStat); // Animate result gsap.from(demoOutput, { @@ -101,6 +98,52 @@ function processText(text) { }); } +function findMaskRanges(text) { + const matches = []; + + Object.values(PATTERNS).forEach((pattern) => { + for (const match of text.matchAll(pattern)) { + matches.push({ + start: match.index, + end: match.index + match[0].length + }); + } + }); + + matches.sort((left, right) => left.start - right.start || right.end - left.end); + + return matches.reduce((ranges, match) => { + const previous = ranges[ranges.length - 1]; + + if (!previous || match.start >= previous.end) { + ranges.push(match); + } else if (match.end > previous.end) { + previous.end = match.end; + } + + return ranges; + }, []); +} + +function renderMaskedText(text, ranges) { + const fragment = document.createDocumentFragment(); + let position = 0; + + ranges.forEach((range) => { + fragment.append(document.createTextNode(text.slice(position, range.start))); + + const highlight = document.createElement('span'); + highlight.className = 'highlight-masked'; + highlight.textContent = '***'; + fragment.append(highlight); + + position = range.end; + }); + + fragment.append(document.createTextNode(text.slice(position))); + demoOutput.replaceChildren(fragment); +} + // Glitch Effect for Title const glitchText = document.querySelector('.glitch-text'); setInterval(() => { diff --git a/openapi.json b/openapi.json index 0b66a40..5eea093 100644 --- a/openapi.json +++ b/openapi.json @@ -277,7 +277,7 @@ "PII Detection" ], "summary": "\ud83d\udd0d Detect PII without modifying content", - "description": "**Scan text or JSON for PII entities without modifying the content.**\n\nUse this endpoint when you only need to identify PII without redacting it.\n\n## Input Modes\n\n### Text Mode\n```json\n{\n \"text\": \"Contact John Doe at john@example.com\"\n}\n```\n\n### JSON Mode\n```json\n{\n \"json\": {\n \"user\": {\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n }\n }\n}\n```\n\n## Detected Entity Types\n\n- **EMAIL**: Email addresses (regex, 100% accuracy)\n- **PHONE**: Phone numbers (international formats, 100% accuracy)\n- **CARD**: Credit card numbers (regex + Luhn validation, 100% accuracy)\n- **PERSON**: Person names (spaCy NER, ~85% accuracy)\n\n## Example Response\n\n```json\n{\n \"entities\": [\n {\n \"type\": \"PERSON\",\n \"value\": \"John Doe\",\n \"start\": 8,\n \"end\": 16\n },\n {\n \"type\": \"EMAIL\",\n \"value\": \"john@example.com\",\n \"start\": 20,\n \"end\": 36\n }\n ]\n}\n```\n\nFor JSON mode, each entity includes a `path` field showing its location (e.g., `\"user.name\"`).", + "description": "**Scan text or JSON for PII entities without modifying the content.**\n\nUse this endpoint when you only need to identify PII without redacting it.\n\n## Input Modes\n\n### Text Mode\n```json\n{\n \"text\": \"Contact John Doe at john@example.com\"\n}\n```\n\n### JSON Mode\n```json\n{\n \"json\": {\n \"user\": {\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n }\n }\n}\n```\n\n## Detected Entity Types\n\n- **EMAIL**: Email addresses (regex)\n- **PHONE**: Phone numbers (international formats, regex)\n- **CARD**: Credit card number candidates (regex)\n- **PERSON**: Person names (spaCy NER)\n\n## Example Response\n\n```json\n{\n \"entities\": [\n {\n \"type\": \"PERSON\",\n \"value\": \"John Doe\",\n \"start\": 8,\n \"end\": 16\n },\n {\n \"type\": \"EMAIL\",\n \"value\": \"john@example.com\",\n \"start\": 20,\n \"end\": 36\n }\n ]\n}\n```\n\nFor JSON mode, each entity includes a `path` field showing its location (e.g., `\"user.name\"`).", "operationId": "detect_pii_api_v1_detect_post", "requestBody": { "content": { diff --git a/pyproject.toml b/pyproject.toml index 6ff4999..a43e924 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,17 +3,16 @@ name = "masker" version = "1.0.0" description = "PII Redaction & Text Anonymization API for LLMs" readme = "README.md" -license = {text = "MIT"} +license = {text = "AGPL-3.0-only"} requires-python = ">=3.11" authors = [ {name = "KikuAI"} ] keywords = ["pii", "redaction", "anonymization", "privacy", "llm", "fastapi"] classifiers = [ - "Development Status :: 5 - Production/Stable", "Framework :: FastAPI", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: GNU Affero General Public License v3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Security",