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.
- datatrust_ai/__init__.py +3 -0
- datatrust_ai/cli.py +61 -0
- datatrust_ai/detector.py +79 -0
- datatrust_ai/normalizer.py +11 -0
- datatrust_ai/patterns/__init__.py +0 -0
- datatrust_ai/patterns/global_ids.py +5 -0
- datatrust_ai/patterns/india.py +16 -0
- datatrust_ai/patterns/nepal.py +19 -0
- datatrust_ai/server.py +39 -0
- datatrust_ai/validators.py +57 -0
- datatrust_privacy_guard-0.1.0.dist-info/METADATA +54 -0
- datatrust_privacy_guard-0.1.0.dist-info/RECORD +15 -0
- datatrust_privacy_guard-0.1.0.dist-info/WHEEL +4 -0
- datatrust_privacy_guard-0.1.0.dist-info/entry_points.txt +3 -0
- datatrust_privacy_guard-0.1.0.dist-info/licenses/LICENSE +21 -0
datatrust_ai/__init__.py
ADDED
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()
|
datatrust_ai/detector.py
ADDED
|
@@ -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,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
|
+
[](https://github.com/warriorxxzz/datatrust-ai/actions/workflows/python-test.yml)
|
|
20
|
+
[](https://opensource.org/licenses/MIT)
|
|
21
|
+
[](https://www.python.org/downloads/)
|
|
22
|
+
|
|
23
|
+

|
|
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,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.
|