datatrust-privacy-guard 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,3 @@
1
+ """DataTrust AI - Local PII Scanner for AI Chats."""
2
+
3
+ __version__ = "0.1.0"
datatrust_ai/cli.py ADDED
@@ -0,0 +1,61 @@
1
+ import sys
2
+ from datatrust_ai.detector import scan_text
3
+
4
+ FRIENDLY_NAMES = {
5
+ "NP_CITIZENSHIP": "Nepal Citizenship Number",
6
+ "NP_NID": "National ID (NID)",
7
+ "NP_PAN": "Nepal PAN Number",
8
+ "NP_PASSPORT": "Nepal Passport Number",
9
+ "NP_PHONE_MOBILE": "Nepal Mobile Number",
10
+ "NP_PHONE_LANDLINE": "Nepal Landline Number",
11
+ "IN_AADHAAR": "India Aadhaar Number",
12
+ "IN_PAN": "India PAN Card",
13
+ "IN_UPI": "India UPI ID",
14
+ "IN_IFSC": "India IFSC Code",
15
+ "IN_PHONE_MOBILE": "India Mobile Number",
16
+ "CREDIT_CARD": "Credit Card Number",
17
+ "EMAIL": "Email Address",
18
+ "IPV4": "IP Address"
19
+ }
20
+
21
+ def print_result(text: str):
22
+ result = scan_text(text)
23
+ risk = result["risk"]
24
+ findings = result["findings"]
25
+
26
+ print("\n" + "="*45)
27
+
28
+ if risk == "NONE":
29
+ print("✅ Looks Safe!")
30
+ print("No personal information was found.")
31
+ print("="*45 + "\n")
32
+ return
33
+
34
+ print("🛑 WARNING: Personal Info Detected!")
35
+ print("="*45)
36
+ print("It looks like you are about to share:\n")
37
+
38
+ detected_types = set()
39
+ for item in findings:
40
+ friendly_name = FRIENDLY_NAMES.get(item['type'], item['type'])
41
+ detected_types.add(friendly_name)
42
+
43
+ for info in detected_types:
44
+ print(f" 🔴 {info}")
45
+
46
+ print("\n⚠️ Please be careful! Once you send this, ")
47
+ print(" the AI will remember it. We recommend ")
48
+ print(" removing these details before sending.")
49
+ print("="*45 + "\n")
50
+
51
+ def main():
52
+ if len(sys.argv) < 2:
53
+ print("Usage: datatrust \"Your text here\"")
54
+ print("Example: datatrust \"My phone is 9841234567\"")
55
+ return
56
+
57
+ text = " ".join(sys.argv[1:])
58
+ print_result(text)
59
+
60
+ if __name__ == "__main__":
61
+ main()
@@ -0,0 +1,79 @@
1
+ import re
2
+ from datatrust_ai.normalizer import normalize_digits
3
+ from datatrust_ai.patterns.nepal import NEPAL_PATTERNS
4
+ from datatrust_ai.patterns.india import INDIA_PATTERNS
5
+ from datatrust_ai.patterns.global_ids import GLOBAL_PATTERNS
6
+ from datatrust_ai.validators import is_valid_luhn, is_valid_verhoeff
7
+
8
+ SEVERITY = {
9
+ # Nepal
10
+ "NP_CITIZENSHIP": "HIGH",
11
+ "NP_NID": "HIGH",
12
+ "NP_PAN": "HIGH",
13
+ "NP_PASSPORT": "HIGH",
14
+ "NP_PHONE_MOBILE": "MEDIUM",
15
+ "NP_PHONE_LANDLINE": "LOW",
16
+ # India
17
+ "IN_AADHAAR": "HIGH",
18
+ "IN_PAN": "HIGH",
19
+ "IN_UPI": "MEDIUM",
20
+ "IN_IFSC": "LOW",
21
+ "IN_PHONE_MOBILE": "MEDIUM",
22
+ # Global
23
+ "CREDIT_CARD": "HIGH",
24
+ "EMAIL": "LOW",
25
+ "IPV4": "LOW",
26
+ }
27
+
28
+ ALL_PATTERNS = {**NEPAL_PATTERNS, **INDIA_PATTERNS, **GLOBAL_PATTERNS}
29
+
30
+ def scan_text(text: str) -> dict:
31
+ normalized = normalize_digits(text)
32
+ findings = []
33
+
34
+ # 1. Run all patterns
35
+ for name, pattern in ALL_PATTERNS.items():
36
+ for match in re.finditer(pattern, normalized):
37
+ value = match.group()
38
+
39
+ # --- CHECKSUM VALIDATION ---
40
+ if name == "CREDIT_CARD" and not is_valid_luhn(value):
41
+ continue # Skip fake credit cards
42
+
43
+ if name == "IN_AADHAAR" and not is_valid_verhoeff(value):
44
+ continue # Skip fake Aadhaar numbers
45
+ # ---------------------------
46
+
47
+ findings.append({
48
+ "type": name,
49
+ "severity": SEVERITY.get(name, "LOW"),
50
+ "start": match.start(),
51
+ "end": match.end(),
52
+ })
53
+
54
+ # 2. Fix overlapping matches (keep the longest match)
55
+ findings.sort(key=lambda x: (x["end"] - x["start"]), reverse=True)
56
+
57
+ filtered = []
58
+ for f in findings:
59
+ overlap = False
60
+ for existing in filtered:
61
+ if max(f["start"], existing["start"]) < min(f["end"], existing["end"]):
62
+ overlap = True
63
+ break
64
+ if not overlap:
65
+ filtered.append(f)
66
+
67
+ # 3. Sort by start position for clean output
68
+ filtered.sort(key=lambda x: x["start"])
69
+
70
+ if any(f["severity"] == "HIGH" for f in filtered):
71
+ risk = "HIGH"
72
+ elif any(f["severity"] == "MEDIUM" for f in filtered):
73
+ risk = "MEDIUM"
74
+ elif filtered:
75
+ risk = "LOW"
76
+ else:
77
+ risk = "NONE"
78
+
79
+ return {"risk": risk, "findings": filtered}
@@ -0,0 +1,11 @@
1
+ DEVANAGARI = "०१२३४५६७८९"
2
+ ARABIC_INDIC = "٠١٢٣٤٥٦٧٨٩"
3
+
4
+ _TRANSLATION = str.maketrans(
5
+ DEVANAGARI + ARABIC_INDIC,
6
+ "0123456789" * 2
7
+ )
8
+
9
+ def normalize_digits(text: str) -> str:
10
+ """Convert Devanagari/Arabic-Indic digits to ASCII digits."""
11
+ return text.translate(_TRANSLATION)
File without changes
@@ -0,0 +1,5 @@
1
+ GLOBAL_PATTERNS = {
2
+ "EMAIL": r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b",
3
+ "CREDIT_CARD": r"\b(?:\d[ -]?){13,19}\b",
4
+ "IPV4": r"\b(?:\d{1,3}\.){3}\d{1,3}\b",
5
+ }
@@ -0,0 +1,16 @@
1
+ INDIA_PATTERNS = {
2
+ # Aadhaar
3
+ "IN_AADHAAR": r"\b[2-9]\d{3}[\s-]?\d{4}[\s-]?\d{4}\b",
4
+
5
+ # PAN
6
+ "IN_PAN": r"\b[A-Z]{5}[0-9]{4}[A-Z]\b",
7
+
8
+ # IFSC Code
9
+ "IN_IFSC": r"\b[A-Z]{4}0[A-Z0-9]{6}\b",
10
+
11
+ # UPI ID
12
+ "IN_UPI": r"\b[a-zA-Z0-9.\-_]{2,256}@[a-zA-Z]{2,64}\b",
13
+
14
+ # Indian Mobile
15
+ "IN_PHONE_MOBILE": r"\b(?:\+91[\s-]?)?[6-9]\d{9}\b",
16
+ }
@@ -0,0 +1,19 @@
1
+ NEPAL_PATTERNS = {
2
+ # Citizenship: e.g., 12-01-78-12345 (Separators are mandatory)
3
+ "NP_CITIZENSHIP": r"\b\d{1,2}[-/\s]\d{1,2}[-/\s]\d{2,4}[-/\s]\d{4,5}\b",
4
+
5
+ # NID: 10 digits, BUT ignores numbers starting with 96, 97, 98 (which are mobiles)
6
+ "NP_NID": r"\b(?!9[678]\d{8})\d{10}\b",
7
+
8
+ # PAN: 9 digits
9
+ "NP_PAN": r"\b\d{9}\b",
10
+
11
+ # Passport: e.g., M1234567 or PA1234567
12
+ "NP_PASSPORT": r"\b(?:[A-Z]\d{7}|[A-Z]{2}\d{6,8})\b",
13
+
14
+ # Mobile: +977 or 98/97/96 followed by 8 digits
15
+ "NP_PHONE_MOBILE": r"\b(?:\+977[- ]?)?9[678]\d{8}\b",
16
+
17
+ # Landline: e.g., 01XXXXXX
18
+ "NP_PHONE_LANDLINE": r"\b0[1-9]\d{6,7}\b",
19
+ }
datatrust_ai/server.py ADDED
@@ -0,0 +1,39 @@
1
+ import json
2
+ from http.server import BaseHTTPRequestHandler, HTTPServer
3
+ from datatrust_ai.detector import scan_text
4
+
5
+ class RequestHandler(BaseHTTPRequestHandler):
6
+ def do_POST(self):
7
+ if self.path == '/scan':
8
+ content_length = int(self.headers['Content-Length'])
9
+ post_data = self.rfile.read(content_length)
10
+
11
+ try:
12
+ data = json.loads(post_data.decode('utf-8'))
13
+ text = data.get('text', '')
14
+ result = scan_text(text)
15
+
16
+ self.send_response(200)
17
+ self.send_header('Content-Type', 'application/json')
18
+ self.send_header('Access-Control-Allow-Origin', '*') # Browser extension ke liye zaroori
19
+ self.end_headers()
20
+ self.wfile.write(json.dumps(result).encode('utf-8'))
21
+ except Exception as e:
22
+ self.send_error(400, str(e))
23
+
24
+
25
+ def do_OPTIONS(self):
26
+ self.send_response(200)
27
+ self.send_header('Access-Control-Allow-Origin', '*')
28
+ self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS')
29
+ self.send_header('Access-Control-Allow-Headers', 'Content-Type')
30
+ self.end_headers()
31
+
32
+ if __name__ == '__main__':
33
+ server = HTTPServer(('127.0.0.1', 8765), RequestHandler)
34
+ print("✅ DataTrust AI Server is Live: http://127.0.0.1:8765")
35
+ try:
36
+ server.serve_forever()
37
+ except KeyboardInterrupt:
38
+ print("\n🛑 Server stopped gracefully.")
39
+ server.server_close()
@@ -0,0 +1,57 @@
1
+ # Mathematical validation algorithms
2
+
3
+ def is_valid_luhn(card_number: str) -> bool:
4
+ """Validates a credit card number using the Luhn algorithm."""
5
+ # Remove spaces and hyphens
6
+ digits = [int(d) for d in str(card_number) if d.isdigit()]
7
+
8
+ # Reverse the digits
9
+ digits = digits[::-1]
10
+
11
+ total = 0
12
+ for i, digit in enumerate(digits):
13
+ if i % 2 == 1: # Double every second digit
14
+ doubled = digit * 2
15
+ total += doubled if doubled < 10 else doubled - 9
16
+ else:
17
+ total += digit
18
+
19
+ return total % 10 == 0
20
+
21
+ def is_valid_verhoeff(aadhaar_number: str) -> bool:
22
+ """Validates an Aadhaar number using the Verhoeff algorithm."""
23
+ # Verhoeff tables
24
+ d = [
25
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
26
+ [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
27
+ [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
28
+ [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
29
+ [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
30
+ [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
31
+ [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
32
+ [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
33
+ [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
34
+ [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
35
+ ]
36
+ p = [
37
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
38
+ [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
39
+ [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
40
+ [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
41
+ [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
42
+ [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
43
+ [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
44
+ [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]
45
+ ]
46
+ inv = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9]
47
+
48
+ # Clean the number
49
+ c = [int(x) for x in str(aadhaar_number) if x.isdigit()]
50
+
51
+ # Reverse and process
52
+ c.reverse()
53
+ check = 0
54
+ for i, digit in enumerate(c):
55
+ check = d[check][p[i % 8][digit]]
56
+
57
+ return check == 0
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.5
2
+ Name: datatrust-privacy-guard
3
+ Version: 0.1.0
4
+ Summary: A local PII scanner for AI chat interfaces. Protects privacy with Nepal/India patterns and checksum validation.
5
+ Author-email: warriorxxzz <warriorxxzz8@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Security
12
+ License-File: LICENSE
13
+ Project-URL: Bug Tracker, https://github.com/warriorxxzz/datatrust-ai/issues
14
+ Project-URL: Homepage, https://github.com/warriorxxzz/datatrust-ai
15
+ Import-Name: datatrust_ai
16
+
17
+ # DataTrust AI
18
+
19
+ [![Python Tests](https://github.com/warriorxxzz/datatrust-ai/actions/workflows/python-test.yml/badge.svg)](https://github.com/warriorxxzz/datatrust-ai/actions/workflows/python-test.yml)
20
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
21
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/downloads/)
22
+
23
+ ![DataTrust AI Demo](demo.jpg)
24
+
25
+ A local PII (Personally Identifiable Information) scanner designed for AI chat interfaces.
26
+
27
+ It checks the text you are about to send to ChatGPT, Claude, or Gemini and warns you if it contains sensitive information like citizenship numbers, PANs, Aadhaar, or phone numbers. Everything runs locally on your device. No data is sent to any server.
28
+
29
+ ## Why this exists
30
+
31
+ People casually paste personal information into AI chats. Once it's in the context window, you can't take it back.
32
+
33
+ Most existing privacy tools are either enterprise-focused or heavily bloated. DataTrust AI is lightweight, built with Python's standard library, and specifically handles local formats like Nepali and Indian IDs. It also uses mathematical checksums to prevent false positives.
34
+
35
+ ## Current Features
36
+
37
+ - **Nepal & India Patterns**: Detects Citizenship, NID, PAN, Aadhaar, UPI, Passport, and mobile numbers.
38
+ - **Devanagari Support**: Automatically normalizes Devanagari digits (`१२३`) to ASCII (`123`) before scanning.
39
+ - **Checksum Validation**: Uses the Luhn algorithm for Credit Cards and the Verhoeff algorithm for Aadhaar to ignore fake numbers.
40
+ - **Privacy-First**: The scanner never returns the actual detected value. It only returns the type and position of the match.
41
+ - **Lightweight**: Zero heavy dependencies. Uses Python's built-in `re` module.
42
+ - **Browser Extension**: Real-time warning banner directly inside the AI chat interface.
43
+
44
+ ## How to use it
45
+
46
+ ### 1. Command Line Interface (CLI)
47
+
48
+ You can install the package locally and use the `datatrust` command.
49
+
50
+ ```bash
51
+ git clone https://github.com/warriorxxzz/datatrust-ai.git
52
+ cd datatrust-ai
53
+ pip install -e .
54
+
@@ -0,0 +1,15 @@
1
+ datatrust_ai/__init__.py,sha256=HHr1B32CR7Jk-AohYUudzyxmFIJt0MkcvF2fnJ3BfWs,76
2
+ datatrust_ai/cli.py,sha256=DhBeTPwSf30kIVbS3JctAh3jDqeS6sT2z1Yry0kE3fY,1781
3
+ datatrust_ai/detector.py,sha256=CmJSR1yrBE8JSGhyrsg0qpIitXdq8jU5nYBKoD3ZUz8,2406
4
+ datatrust_ai/normalizer.py,sha256=gnauv-ERhWDgj5VO0CoOErYMqdhB90okuEXSUgCUHAs,316
5
+ datatrust_ai/server.py,sha256=ouygpyOlGBUqO2hu9imGQoRd-OqQxNwH_VZTdgT_KVo,1537
6
+ datatrust_ai/validators.py,sha256=_HsSLJHjymhcCM2HY44Yx1q4SwYzAE9JdjeQquF820Y,1772
7
+ datatrust_ai/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ datatrust_ai/patterns/global_ids.py,sha256=KKaLNmoKhvqjmh8qjy1-6ETYiVvboDvMdyqbEXTgS3I,180
9
+ datatrust_ai/patterns/india.py,sha256=GFUaLSxcjGAnK1xf0ZGICl6q3qN6bZYKq3FmEuB8ZI8,378
10
+ datatrust_ai/patterns/nepal.py,sha256=ycbpY5isWEUO2yLguMecPr_xBm45ajfSkp-tp_8y0KA,659
11
+ datatrust_privacy_guard-0.1.0.dist-info/entry_points.txt,sha256=9zMxbVdLSIwxXJxTCuiuhgFR0VrrS5ZgZTVMe19VFIw,51
12
+ datatrust_privacy_guard-0.1.0.dist-info/licenses/LICENSE,sha256=_ZbbW42kK_G4YsGBNQl91x9Q6pmJ2KAmLz3iWRaovzA,1068
13
+ datatrust_privacy_guard-0.1.0.dist-info/WHEEL,sha256=lqN8jXt_QloFOGcx9kStvWbryhfEXoI2F2z-YURm350,81
14
+ datatrust_privacy_guard-0.1.0.dist-info/METADATA,sha256=XNfDWrz7HeJFQC5Vtt_wRLFCtY7gvZ-cFq9WU-LY9q4,2772
15
+ datatrust_privacy_guard-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: flit 4.1.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ datatrust=datatrust_ai.cli:main
3
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 warriorxxzz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.