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:
|
||||
# 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-<username>.
|
||||
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}"
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user