feat(domains): support username root domain claims
Build and publish Docker image / build-and-publish (push) Successful in 9s
Build and publish Docker image / build-and-publish (push) Successful in 9s
This commit is contained in:
1 parent
2768f5f97d
commit
079140ce49
4 files changed
+19
-14
No files matched your search
+11
-6
@@ -463,7 +463,7 @@ class DomainManager:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Validate inputs
|
# Validate inputs
|
||||||
if not username or not subdomain_name:
|
if not username or subdomain_name is None:
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
'message': "Username and subdomain name are required",
|
'message': "Username and subdomain name are required",
|
||||||
@@ -478,7 +478,7 @@ class DomainManager:
|
|||||||
return {'success': False, 'message': "Username cannot be represented as a DNS name", 'domain_data': None}
|
return {'success': False, 'message': "Username cannot be represented as a DNS name", 'domain_data': None}
|
||||||
|
|
||||||
# Hostnames are single labels below u-<username>.
|
# Hostnames are single labels below u-<username>.
|
||||||
if not self._is_valid_subdomain(subdomain_name):
|
if subdomain_name and not self._is_valid_subdomain(subdomain_name):
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
'message': "Invalid subdomain name. Use only letters, numbers, and hyphens",
|
'message': "Invalid subdomain name. Use only letters, numbers, and hyphens",
|
||||||
@@ -487,7 +487,7 @@ class DomainManager:
|
|||||||
|
|
||||||
# Construct domains
|
# Construct domains
|
||||||
user_domain = f"u-{username}.{self.base_domain}"
|
user_domain = f"u-{username}.{self.base_domain}"
|
||||||
full_subdomain = f"{subdomain_name}.{user_domain}"
|
full_subdomain = f"{subdomain_name}.{user_domain}" if subdomain_name else user_domain
|
||||||
namespace = self.ensure_user_namespace(username)
|
namespace = self.ensure_user_namespace(username)
|
||||||
if not namespace['success']:
|
if not namespace['success']:
|
||||||
return {'success': False, 'message': namespace['message'], 'domain_data': None}
|
return {'success': False, 'message': namespace['message'], 'domain_data': None}
|
||||||
@@ -631,7 +631,7 @@ class DomainManager:
|
|||||||
def delete_subdomain(self, username: str, subdomain_name: str) -> Dict:
|
def delete_subdomain(self, username: str, subdomain_name: str) -> Dict:
|
||||||
"""Delete a subdomain"""
|
"""Delete a subdomain"""
|
||||||
try:
|
try:
|
||||||
if not username or not subdomain_name:
|
if not username or subdomain_name is None:
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
'message': "Username and subdomain name are required"
|
'message': "Username and subdomain name are required"
|
||||||
@@ -639,9 +639,14 @@ class DomainManager:
|
|||||||
|
|
||||||
username = username.lower().strip()
|
username = username.lower().strip()
|
||||||
subdomain_name = subdomain_name.lower().strip()
|
subdomain_name = subdomain_name.lower().strip()
|
||||||
if not self._is_valid_username_label(username) or not self._is_valid_subdomain(subdomain_name):
|
if not self._is_valid_username_label(username):
|
||||||
return {'success': False, 'message': "Invalid username or subdomain"}
|
return {'success': False, 'message': "Invalid username or subdomain"}
|
||||||
user_domain = f"u-{username}.{self.base_domain}"
|
user_domain = f"u-{username}.{self.base_domain}"
|
||||||
|
# Releasing the optional root claim must never remove the shared namespace DNS.
|
||||||
|
if not subdomain_name:
|
||||||
|
return {'success': True, 'message': f"Domain claim {user_domain} deleted"}
|
||||||
|
if not self._is_valid_subdomain(subdomain_name):
|
||||||
|
return {'success': False, 'message': "Invalid username or subdomain"}
|
||||||
full_subdomain = f"{subdomain_name}.{user_domain}"
|
full_subdomain = f"{subdomain_name}.{user_domain}"
|
||||||
|
|
||||||
# New namespaces use a shared wildcard in the parent zone. Do not
|
# New namespaces use a shared wildcard in the parent zone. Do not
|
||||||
@@ -848,7 +853,7 @@ class DomainManager:
|
|||||||
subdomain_name = subdomain_name.lower().strip()
|
subdomain_name = subdomain_name.lower().strip()
|
||||||
|
|
||||||
# First validate the subdomain name
|
# First validate the subdomain name
|
||||||
if not self._is_valid_subdomain(subdomain_name):
|
if subdomain_name and not self._is_valid_subdomain(subdomain_name):
|
||||||
return {
|
return {
|
||||||
'available': False,
|
'available': False,
|
||||||
'message': f"Invalid subdomain name: {subdomain_name}"
|
'message': f"Invalid subdomain name: {subdomain_name}"
|
||||||
|
|||||||
+2
-2
@@ -113,10 +113,10 @@ def create_domain_api():
|
|||||||
return jsonify({'error': 'Domain service not available'}), 503
|
return jsonify({'error': 'Domain service not available'}), 503
|
||||||
|
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
subdomain = data.get('subdomain')
|
subdomain = '' if data.get('useUsernameDomain') is True else data.get('subdomain')
|
||||||
server_id = data.get('serverId')
|
server_id = data.get('serverId')
|
||||||
|
|
||||||
if not subdomain:
|
if subdomain is None:
|
||||||
return jsonify({'error': 'Subdomain name required'}), 400
|
return jsonify({'error': 'Subdomain name required'}), 400
|
||||||
|
|
||||||
# Check if subdomain is available
|
# Check if subdomain is available
|
||||||
|
|||||||
@@ -258,9 +258,9 @@ def apply_plan(api: DeSec, namespaces: Iterable[str], copies: List[Dict],
|
|||||||
UPDATE user_domains
|
UPDATE user_domains
|
||||||
SET record_type = ?, ip_address = ?, ttl = 3600
|
SET record_type = ?, ip_address = ?, ttl = 3600
|
||||||
WHERE COALESCE(is_custom, FALSE) = FALSE
|
WHERE COALESCE(is_custom, FALSE) = FALSE
|
||||||
AND lower(full_domain) LIKE ? ESCAPE '!'
|
AND (lower(full_domain) = ? OR lower(full_domain) LIKE ? ESCAPE '!')
|
||||||
""",
|
""",
|
||||||
('CNAME', api.base_domain, pattern),
|
('CNAME', api.base_domain, f'{namespace}.{api.base_domain}', pattern),
|
||||||
)
|
)
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
||||||
|
|||||||
@@ -1383,12 +1383,12 @@ async def handle_create_domain(client_id, data):
|
|||||||
|
|
||||||
user_id = client_info['user_id']
|
user_id = client_info['user_id']
|
||||||
username = client_info['username']
|
username = client_info['username']
|
||||||
subdomain_name = data.get('subdomain')
|
subdomain_name = '' if data.get('useUsernameDomain') is True else data.get('subdomain')
|
||||||
server_id = data.get('serverId')
|
server_id = data.get('serverId')
|
||||||
|
|
||||||
logger.info(f"DEBUG: Creating domain for user {username}, subdomain: {subdomain_name}")
|
logger.info(f"DEBUG: Creating domain for user {username}, subdomain: {subdomain_name}")
|
||||||
|
|
||||||
if not subdomain_name:
|
if subdomain_name is None:
|
||||||
await send_message(client_id, {'type': 'error', 'error': 'Subdomain name required'})
|
await send_message(client_id, {'type': 'error', 'error': 'Subdomain name required'})
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1398,7 +1398,7 @@ async def handle_create_domain(client_id, data):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Validate subdomain name
|
# Validate subdomain name
|
||||||
if not domain_manager._is_valid_subdomain(subdomain_name):
|
if subdomain_name and not domain_manager._is_valid_subdomain(subdomain_name):
|
||||||
await send_message(client_id, {'type': 'error', 'error': 'Invalid subdomain name. Use only lowercase letters, numbers, and hyphens (1-63 chars)'})
|
await send_message(client_id, {'type': 'error', 'error': 'Invalid subdomain name. Use only lowercase letters, numbers, and hyphens (1-63 chars)'})
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1409,7 +1409,7 @@ async def handle_create_domain(client_id, data):
|
|||||||
try:
|
try:
|
||||||
# Check if subdomain is available (improved check)
|
# Check if subdomain is available (improved check)
|
||||||
user_domain = f"u-{username}.{domain_manager.base_domain}"
|
user_domain = f"u-{username}.{domain_manager.base_domain}"
|
||||||
full_subdomain = f"{subdomain_name}.{user_domain}"
|
full_subdomain = f"{subdomain_name}.{user_domain}" if subdomain_name else user_domain
|
||||||
|
|
||||||
# Check if domain already exists in database
|
# Check if domain already exists in database
|
||||||
with database_connection() as conn:
|
with database_connection() as conn:
|
||||||
|
|||||||
Reference in new issue
Block a user