diff --git a/domain_manager.py b/domain_manager.py index 955fd26..e5af142 100644 --- a/domain_manager.py +++ b/domain_manager.py @@ -463,7 +463,7 @@ class DomainManager: """ try: # Validate inputs - if not username or not subdomain_name: + if not username or subdomain_name is None: return { 'success': False, '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} # Hostnames are single labels below u-. - if not self._is_valid_subdomain(subdomain_name): + if subdomain_name and not self._is_valid_subdomain(subdomain_name): return { 'success': False, 'message': "Invalid subdomain name. Use only letters, numbers, and hyphens", @@ -487,7 +487,7 @@ class DomainManager: # Construct domains 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) if not namespace['success']: 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: """Delete a subdomain""" try: - if not username or not subdomain_name: + if not username or subdomain_name is None: return { 'success': False, 'message': "Username and subdomain name are required" @@ -639,9 +639,14 @@ class DomainManager: username = username.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"} 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}" # New namespaces use a shared wildcard in the parent zone. Do not @@ -848,7 +853,7 @@ class DomainManager: subdomain_name = subdomain_name.lower().strip() # 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 { 'available': False, 'message': f"Invalid subdomain name: {subdomain_name}" diff --git a/routes/domains.py b/routes/domains.py index 8213fcf..a057ca8 100644 --- a/routes/domains.py +++ b/routes/domains.py @@ -113,10 +113,10 @@ def create_domain_api(): return jsonify({'error': 'Domain service not available'}), 503 data = request.get_json() - subdomain = data.get('subdomain') + subdomain = '' if data.get('useUsernameDomain') is True else data.get('subdomain') server_id = data.get('serverId') - if not subdomain: + if subdomain is None: return jsonify({'error': 'Subdomain name required'}), 400 # Check if subdomain is available diff --git a/scripts/migrate_delegated_dns.py b/scripts/migrate_delegated_dns.py index c0b682f..ae319e7 100644 --- a/scripts/migrate_delegated_dns.py +++ b/scripts/migrate_delegated_dns.py @@ -258,9 +258,9 @@ def apply_plan(api: DeSec, namespaces: Iterable[str], copies: List[Dict], UPDATE user_domains SET record_type = ?, ip_address = ?, ttl = 3600 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() diff --git a/websocket_service.py b/websocket_service.py index 38dddfd..0108e86 100644 --- a/websocket_service.py +++ b/websocket_service.py @@ -1383,12 +1383,12 @@ async def handle_create_domain(client_id, data): user_id = client_info['user_id'] 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') 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'}) return @@ -1398,7 +1398,7 @@ async def handle_create_domain(client_id, data): return # 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)'}) return @@ -1409,7 +1409,7 @@ async def handle_create_domain(client_id, data): try: # Check if subdomain is available (improved check) 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 with database_connection() as conn: