mckabue commited on
Commit
8a21bc0
·
0 Parent(s):

Add initial implementation of Private Domain Checker with Docker support

Browse files

- Create Dockerfile for containerization
- Add Flask application for domain availability checking
- Implement domain checking logic using DNS, RDAP, and WHOIS
- Add HTML frontend for user interaction
- Include requirements.txt for dependencies
- Add .gitignore to exclude Python cache files
- Create README.md for project documentation

Files changed (6) hide show
  1. .gitignore +1 -0
  2. Dockerfile +16 -0
  3. README.md +9 -0
  4. app.py +125 -0
  5. index.html +73 -0
  6. requirements.txt +2 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ __pycache__/app.cpython-310.pyc
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
+ # you will also find guides on how best to write your Dockerfile
3
+
4
+ FROM python:3.9
5
+
6
+ RUN useradd -m -u 1000 user
7
+
8
+ WORKDIR /app
9
+
10
+ COPY --chown=user ./requirements.txt requirements.txt
11
+
12
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
13
+
14
+ COPY --chown=user . /app
15
+
16
+ CMD ["gunicorn", "-b", "0.0.0.0:7860", "app:app"]
README.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Private Domain Checker | ToKnow.ai
3
+ emoji: 🏢
4
+ colorFrom: blue
5
+ colorTo: gray
6
+ sdk: docker
7
+ pinned: false
8
+ license: gpl-3.0
9
+ ---
app.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, send_from_directory
2
+ import dns.resolver
3
+ import socket
4
+ import requests
5
+ from urllib.parse import urlparse
6
+ import dns.resolver
7
+ import socket
8
+
9
+ app = Flask(__name__)
10
+
11
+ @app.route('/')
12
+ def index():
13
+ """Route handler for the home page"""
14
+ try:
15
+ return send_from_directory('.', 'index.html')
16
+ except Exception as e:
17
+ return str(e)
18
+
19
+ @app.route('/check', methods=['POST'])
20
+ def check_domain():
21
+ """Check domain availability"""
22
+ try:
23
+ domain = request.json.get('domain', '').strip().lower().strip('/')
24
+ if '://' in domain:
25
+ domain = urlparse(domain).netloc
26
+ result = check_domain_availability(domain) or {}
27
+ return {
28
+ "domain": domain,
29
+ "available": result.get("available"),
30
+ "method": result.get("method", None),
31
+ "error": result.get("error", None)
32
+ }
33
+ except Exception as e:
34
+ return { "domain": domain, "error": str(e) }
35
+
36
+ def check_domain_availability(domain):
37
+ """Check domain availability using multiple methods."""
38
+ # First try DNS resolution
39
+ dns_exists, record_type = check_dns_records(domain)
40
+ if dns_exists:
41
+ return { "available": False, "method": f"DNS:{record_type}" }
42
+
43
+ # Try RDAP
44
+ rdap_status_code, rdap_base_url = check_rdap_records(domain)
45
+ if rdap_status_code == 404:
46
+ return { "available": True, "method": f"RDAP:{rdap_base_url}" }
47
+ elif rdap_status_code == 200:
48
+ return { "available": False, "method": f"RDAP:{rdap_base_url}" }
49
+
50
+ # Fall back to WHOIS
51
+ whois_server = get_whois_server(domain)
52
+ if whois_server and no_whois_records(domain, whois_server):
53
+ return {"available": True, "method": f"WHOIS:{whois_server}"}
54
+
55
+ def get_whois_server(domain):
56
+ """Get WHOIS server from IANA root zone database."""
57
+ try:
58
+ response = requests.get(f'https://www.iana.org/whois?q={domain}')
59
+ if 'whois:' in response.text.lower():
60
+ for line in response.text.split('\n'):
61
+ if 'whois:' in line.lower():
62
+ return line.split(':')[1].strip()
63
+ except:
64
+ pass
65
+ return None
66
+
67
+ def check_dns_records(domain):
68
+ """Check if domain exists in DNS by looking for common record types."""
69
+ # Check NS records first as they're required for valid domains
70
+ for record_type in ['NS', 'A', 'AAAA', 'MX', 'CNAME']:
71
+ try:
72
+ dns.resolver.resolve(domain, record_type)
73
+ return True, record_type
74
+ except:
75
+ continue
76
+ return False, None
77
+
78
+ def check_rdap_records(domain):
79
+ try:
80
+ bootstrap_url = "https://data.iana.org/rdap/dns.json"
81
+ bootstrap_data = requests.get(bootstrap_url, timeout=5).json()
82
+
83
+ tld = domain.split('.')[-1]
84
+ rdap_base_url = None
85
+
86
+ for service in bootstrap_data['services']:
87
+ if tld in service[0]:
88
+ rdap_base_url = service[1][0].strip('/')
89
+ break
90
+
91
+ if rdap_base_url:
92
+ rdap_url = f"{rdap_base_url}/domain/{domain}"
93
+ response = requests.get(rdap_url, timeout=5)
94
+ return response.status_code, rdap_base_url
95
+ except:
96
+ pass
97
+ return None, None
98
+
99
+ def no_whois_records(domain, whois_server) -> bool:
100
+ try:
101
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
102
+ sock.settimeout(5)
103
+ sock.connect((whois_server, 43))
104
+ sock.send(f"{domain}\r\n".encode())
105
+ response = sock.recv(4096).decode(errors='ignore')
106
+ sock.close()
107
+
108
+ available_patterns = [
109
+ 'no match',
110
+ 'not found',
111
+ 'no entries found',
112
+ 'no data found',
113
+ 'not registered',
114
+ 'available',
115
+ 'status: free',
116
+ 'domain not found'
117
+ ]
118
+
119
+ response_lower = response.lower()
120
+ for pattern in available_patterns:
121
+ if pattern in response_lower:
122
+ return True
123
+ except:
124
+ pass
125
+ return False
index.html ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <title>Private Domain Checker | ToKnow.ai</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ </head>
9
+
10
+ <body class="bg-light">
11
+ <div class="container mt-5">
12
+ <div class="row justify-content-center">
13
+ <div class="col-md-6">
14
+ <div class="card">
15
+ <div class="card-body">
16
+ <h3 class="text-center mb-4">Private Domain Checker - ToKnow.ai</h3>
17
+ <form id="searchForm" class="mb-3">
18
+ <div class="input-group">
19
+ <input type="text" id="domain" class="form-control" placeholder="Enter domain name...">
20
+ <button class="btn btn-primary" type="submit">Check</button>
21
+ </div>
22
+ </form>
23
+ <div id="result" class="text-center d-none">
24
+ <div class="spinner-border text-primary d-none" id="spinner"></div>
25
+ <div id="resultText"></div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+
33
+ <script>
34
+ document.getElementById('searchForm').onsubmit = async (e) => {
35
+ e.preventDefault();
36
+ const domain = document.getElementById('domain').value;
37
+ const result = document.getElementById('result');
38
+ const spinner = document.getElementById('spinner');
39
+ const resultText = document.getElementById('resultText');
40
+
41
+ result.classList.remove('d-none');
42
+ spinner.classList.remove('d-none');
43
+ resultText.innerHTML = '';
44
+
45
+ try {
46
+ const response = await fetch('/check', {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify({ domain })
50
+ });
51
+
52
+ const data = await response.json();
53
+
54
+ resultText.innerHTML = `
55
+ <div class="alert ${data.available ? 'alert-success' : 'alert-danger'} mt-3">
56
+ <strong>${domain}</strong> is ${data.available ? 'available' : 'not available'}
57
+ ${data.method ? `<br>(checked via ${data.method})` : ''}
58
+ ${data.error ? `<br>(error: ${data.error})` : ''}
59
+ </div>
60
+ `;
61
+ } catch (err) {
62
+ resultText.innerHTML = `
63
+ <div class="alert alert-warning mt-3">
64
+ Error checking domain
65
+ </div>
66
+ `;
67
+ }
68
+ spinner.classList.add('d-none');
69
+ };
70
+ </script>
71
+ </body>
72
+
73
+ </html>
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ flask==3.0.3
2
+ dnspython==2.7.0