mirror of
https://github.com/ChrispyBacon-dev/DockFlare.git
synced 2026-04-28 03:39:32 +00:00
Manual rule Access Group Policy feature added
This commit is contained in:
parent
c85ecbb57c
commit
c1add43747
3 changed files with 324 additions and 302 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// app/static/js/main.js
|
||||
// app/static/js/main.js - painful .. javascript
|
||||
const maxLogLines = 250;
|
||||
let initialConnectMessageCleared = false;
|
||||
let activeLogSource = null;
|
||||
|
|
@ -101,7 +101,7 @@ function initializeEditManualRuleModal() {
|
|||
|
||||
modal.querySelector('#edit_original_rule_key').value = ruleKey;
|
||||
|
||||
const hostname = details.hostname_for_dns || '';
|
||||
const hostname = details.hostname || '';
|
||||
const parts = hostname.split('.');
|
||||
if (parts.length > 2 && !hostname.startsWith('*.')) {
|
||||
modal.querySelector('#edit_manual_subdomain').value = parts.slice(0, -2).join('.');
|
||||
|
|
@ -110,38 +110,39 @@ function initializeEditManualRuleModal() {
|
|||
modal.querySelector('#edit_manual_subdomain').value = '';
|
||||
modal.querySelector('#edit_manual_domain_name').value = hostname;
|
||||
}
|
||||
|
||||
const path = details.path || '';
|
||||
const pathDisplayInput = modal.querySelector('#edit_manual_path_display');
|
||||
pathDisplayInput.value = path.startsWith('/') ? path.substring(1) : path;
|
||||
modal.querySelector('#edit_manual_path_display').value = path.startsWith('/') ? path.substring(1) : path;
|
||||
modal.querySelector('#edit_manual_path').value = path;
|
||||
|
||||
const service = details.service || '';
|
||||
const serviceParts = service.split('://');
|
||||
let serviceType = '';
|
||||
let serviceAddress = '';
|
||||
|
||||
if (serviceParts.length === 2) {
|
||||
serviceType = serviceParts[0];
|
||||
serviceAddress = serviceParts[1];
|
||||
modal.querySelector('#edit_manual_service_type').value = serviceParts[0];
|
||||
modal.querySelector('#edit_manual_service_address').value = serviceParts[1];
|
||||
} else if (service.startsWith('http_status:')) {
|
||||
serviceType = 'http_status';
|
||||
serviceAddress = service.split(':')[1];
|
||||
modal.querySelector('#edit_manual_service_type').value = 'http_status';
|
||||
modal.querySelector('#edit_manual_service_address').value = service.split(':')[1];
|
||||
}
|
||||
modal.querySelector('#edit_manual_service_type').value = serviceType;
|
||||
modal.querySelector('#edit_manual_service_address').value = serviceAddress;
|
||||
|
||||
const policyType = details.access_policy_type || 'none';
|
||||
const policySelect = modal.querySelector('#edit_manual_access_policy_type');
|
||||
policySelect.value = policyType;
|
||||
const accessGroupSelect = modal.querySelector('#edit_manual_access_group');
|
||||
const manualPolicySelect = modal.querySelector('#edit_manual_access_policy_type');
|
||||
|
||||
if (details.access_group_id) {
|
||||
accessGroupSelect.value = details.access_group_id;
|
||||
} else {
|
||||
accessGroupSelect.value = '';
|
||||
}
|
||||
|
||||
policySelect.dispatchEvent(new Event('change'));
|
||||
manualPolicySelect.value = details.access_policy_type || 'none';
|
||||
|
||||
accessGroupSelect.dispatchEvent(new Event('change'));
|
||||
manualPolicySelect.dispatchEvent(new Event('change'));
|
||||
|
||||
modal.querySelector('#edit_manual_auth_email').value = details.auth_email || '';
|
||||
modal.querySelector('#edit_manual_zone_name_override').value = '';
|
||||
modal.querySelector('#edit_manual_no_tls_verify').checked = details.no_tls_verify || false;
|
||||
modal.querySelector('#edit_manual_origin_server_name').value = details.origin_server_name || '';
|
||||
modal.querySelector('#edit_manual_http_host_header').value = details.http_host_header || '';
|
||||
|
||||
modal.showModal();
|
||||
} catch (e) {
|
||||
console.error("Error populating edit modal:", e);
|
||||
|
|
@ -445,6 +446,8 @@ function openEditAccessGroupModal(groupId, details) {
|
|||
policy.include.forEach(rule => {
|
||||
if (rule.email && rule.email.email) {
|
||||
emails.push(rule.email.email);
|
||||
} else if (rule.email_domain && rule.email_domain.domain) {
|
||||
emails.push(`@${rule.email_domain.domain}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -521,6 +524,33 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
initializeEditManualRuleModal();
|
||||
}
|
||||
|
||||
// Logic for new Access Group dropdown in ADD Manual Rule Modal
|
||||
const manualAccessGroupSelect = document.getElementById('manual_access_group');
|
||||
const manualPolicyOptionsWrapper = document.getElementById('manual_policy_options_wrapper');
|
||||
if (manualAccessGroupSelect && manualPolicyOptionsWrapper) {
|
||||
manualAccessGroupSelect.addEventListener('change', function() {
|
||||
const isDisabled = !!this.value;
|
||||
manualPolicyOptionsWrapper.style.opacity = isDisabled ? '0.5' : '1';
|
||||
manualPolicyOptionsWrapper.querySelectorAll('select, input').forEach(el => {
|
||||
el.disabled = isDisabled;
|
||||
});
|
||||
});
|
||||
manualAccessGroupSelect.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
// Logic for new Access Group dropdown in EDIT Manual Rule Modal
|
||||
const editManualAccessGroupSelect = document.getElementById('edit_manual_access_group');
|
||||
const editManualPolicyOptionsWrapper = document.getElementById('edit_manual_policy_options_wrapper');
|
||||
if (editManualAccessGroupSelect && editManualPolicyOptionsWrapper) {
|
||||
editManualAccessGroupSelect.addEventListener('change', function() {
|
||||
const isDisabled = !!this.value;
|
||||
editManualPolicyOptionsWrapper.style.opacity = isDisabled ? '0.5' : '1';
|
||||
editManualPolicyOptionsWrapper.querySelectorAll('select, input').forEach(el => {
|
||||
el.disabled = isDisabled;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Setup for Access Group Modal (only if on Access Groups Page)
|
||||
document.querySelectorAll('.edit-access-group-btn').forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
|
|
|
|||
|
|
@ -432,12 +432,33 @@
|
|||
<div id="manual_service_help" class="text-xs opacity-60 mt-1">e.g., 192.168.1.10:8000 or my-service.local:3000 for HTTP/S/TCP etc.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-md font-semibold mb-2">Access Policy (Optional)</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 items-start">
|
||||
<div>
|
||||
<label class="label" for="manual_access_policy_type"><span class="label-text">Policy Type</span></label>
|
||||
<h4 class="text-md font-semibold mb-2">Access Policy (Optional)</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 items-start p-4 rounded-md bg-base-200/50">
|
||||
|
||||
<!-- NEW: Access Group Dropdown -->
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="manual_access_group">
|
||||
<span class="label-text font-medium">1. Assign an Access Group (Recommended)</span>
|
||||
</label>
|
||||
<select name="manual_access_group" id="manual_access_group" class="select select-bordered w-full">
|
||||
<option value="" selected>-- None (Configure Manually Below) --</option>
|
||||
{% if access_groups %}
|
||||
{% for group_id, details in access_groups.items()|sort %}
|
||||
<option value="{{ group_id }}">{{ details.display_name }} (ID: {{ group_id }})</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</select>
|
||||
<div class="label"><span class="label-text-alt">Using a group overrides the manual policy options below.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="divider md:col-span-2 text-xs opacity-80 my-0">OR</div>
|
||||
<div id="manual_policy_options_wrapper" class="md:col-span-2 grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
||||
<div class="form-control">
|
||||
<label class="label" for="manual_access_policy_type">
|
||||
<span class="label-text font-medium">2. Configure Manually</span>
|
||||
</label>
|
||||
<select name="manual_access_policy_type" id="manual_access_policy_type" class="select select-bordered w-full policy-type-select">
|
||||
<option value="none" selected>None (Public - No App)</option>
|
||||
<option value="bypass">Bypass (Public App)</option>
|
||||
|
|
@ -445,57 +466,14 @@
|
|||
<option value="default_tld">Use Default *.tld Policy</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="auth-email-field hidden md:col-span-1">
|
||||
<div class="auth-email-field hidden">
|
||||
<label class="label" for="manual_auth_email"><span class="label-text">Allowed Email(s) or Domain(s)</span></label>
|
||||
<input type="text" id="manual_auth_email" name="manual_auth_email" placeholder="user@example.com, @domain.com" class="input input-bordered w-full" />
|
||||
<div class="text-xs opacity-60 mt-1">Comma-separated. e.g., test@example.com, @another.org</div>
|
||||
<div class="label"><span class="label-text-alt">Comma-separated. e.g., test@example.com, @another.org</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4 pt-4 border-t border-base-300 mt-6">
|
||||
<div>
|
||||
<label class="label" for="manual_zone_name_override"><span class="label-text">Cloudflare Zone Name (Override/Specific)</span></label>
|
||||
<input type="text" id="manual_zone_name_override" name="manual_zone_name_override" placeholder="yourdomain.com (if different from Domain Name or CF_ZONE_ID)" class="input input-bordered w-full" />
|
||||
{% if CF_ZONE_ID_CONFIGURED and CF_ZONE_ID %}
|
||||
<div class="text-xs opacity-60 mt-1">If blank, DockFlare will use "Domain Name" or default CF_ZONE_ID ({{ CF_ZONE_ID[:12] }}...). Target a different Zone if needed.</div>
|
||||
{% else %}
|
||||
<div class="text-xs opacity-60 mt-1">If blank, DockFlare will use "Domain Name". Target a specific Zone if "Domain Name" is ambiguous or CF_ZONE_ID is not set.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="manual_no_tls_verify_div" class="form-control">
|
||||
<label class="label cursor-pointer justify-start gap-2">
|
||||
<input type="checkbox" name="manual_no_tls_verify" id="manual_no_tls_verify" class="checkbox checkbox-sm" />
|
||||
<span class="label-text">Disable TLS Verification (No TLS Verify)</span>
|
||||
</label>
|
||||
<div class="text-xs opacity-60 ml-8">Check if the origin service uses self-signed SSL or is HTTP. (Only applies to HTTP/HTTPS services).</div>
|
||||
</div>
|
||||
<div class="form-control" id="manual_origin_server_name_div">
|
||||
<label class="label" for="manual_origin_server_name">
|
||||
<span class="label-text">Origin Server Name (SNI for TLS)</span>
|
||||
</label>
|
||||
<input type="text" id="manual_origin_server_name" name="manual_origin_server_name"
|
||||
placeholder="e.g., internal.service.local (optional)"
|
||||
class="input input-bordered w-full" />
|
||||
<label class="label">
|
||||
<span class="label-text-alt">Specify the hostname Cloudflare should use for TLS SNI when connecting to your origin. Leave blank if not needed. (Only applies to HTTP/HTTPS services).</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label" for="manual_http_host_header">
|
||||
<span class="label-text">HTTP Host Header (Optional)</span>
|
||||
</label>
|
||||
<input type="text" id="manual_http_host_header" name="manual_http_host_header"
|
||||
placeholder="e.g., api.example.com"
|
||||
class="input input-bordered w-full" />
|
||||
<label class="label">
|
||||
<span class="label-text-alt">Overrides the <code>Host</code> header sent to your origin server. Useful for origins expecting a different hostname than the public one. (Only applies to HTTP/HTTPS services).</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-action mt-8">
|
||||
<button type="submit" class="btn btn-primary">Add Rule</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<form method="dialog" class="modal-backdrop"><button>close</button></form>
|
||||
</dialog>
|
||||
|
||||
|
|
@ -551,11 +529,35 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-md font-semibold mb-2">Access Policy (Optional)</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 items-start">
|
||||
<div>
|
||||
<label class="label" for="edit_manual_access_policy_type"><span class="label-text">Policy Type</span></label>
|
||||
|
||||
<div>
|
||||
<h4 class="text-md font-semibold mb-2">Access Policy (Optional)</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 items-start p-4 rounded-md bg-base-200/50">
|
||||
|
||||
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="edit_manual_access_group">
|
||||
<span class="label-text font-medium">1. Assign an Access Group (Recommended)</span>
|
||||
</label>
|
||||
<select name="manual_access_group" id="edit_manual_access_group" class="select select-bordered w-full">
|
||||
<option value="">-- None (Configure Manually Below) --</option>
|
||||
{% if access_groups %}
|
||||
{% for group_id, details in access_groups.items()|sort %}
|
||||
<option value="{{ group_id }}">{{ details.display_name }} (ID: {{ group_id }})</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</select>
|
||||
<div class="label"><span class="label-text-alt">Using a group overrides the manual policy options below.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="divider md:col-span-2 text-xs opacity-80 my-0">OR</div>
|
||||
|
||||
|
||||
<div id="edit_manual_policy_options_wrapper" class="md:col-span-2 grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
||||
<div class="form-control">
|
||||
<label class="label" for="edit_manual_access_policy_type">
|
||||
<span class="label-text font-medium">2. Configure Manually</span>
|
||||
</label>
|
||||
<select name="manual_access_policy_type" id="edit_manual_access_policy_type" class="select select-bordered w-full policy-type-select">
|
||||
<option value="none">None (Public - No App)</option>
|
||||
<option value="bypass">Bypass (Public App)</option>
|
||||
|
|
@ -563,12 +565,14 @@
|
|||
<option value="default_tld">Use Default *.tld Policy</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="auth-email-field hidden md:col-span-1">
|
||||
<div class="auth-email-field hidden">
|
||||
<label class="label" for="edit_manual_auth_email"><span class="label-text">Allowed Email(s) or Domain(s)</span></label>
|
||||
<input type="text" id="edit_manual_auth_email" name="manual_auth_email" placeholder="user@example.com, @domain.com" class="input input-bordered w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4 pt-4 border-t border-base-300 mt-6">
|
||||
<div class="form-control">
|
||||
<label class="label" for="edit_manual_zone_name_override"><span class="label-text">Cloudflare Zone Name (Override/Specific)</span></label>
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ def status_page():
|
|||
tld_policy_exists_val = False
|
||||
account_email_for_tld_val = None
|
||||
relevant_zone_name_for_tld_policy_val = None
|
||||
template_access_groups = {}
|
||||
|
||||
with state_lock:
|
||||
for hostname, rule in managed_rules.items():
|
||||
|
|
@ -124,6 +125,7 @@ def status_page():
|
|||
rules_for_template[hostname] = rule_copy
|
||||
template_tunnel_state = tunnel_state.copy()
|
||||
template_agent_state = cloudflared_agent_state.copy()
|
||||
template_access_groups = copy.deepcopy(access_groups)
|
||||
|
||||
initialization_status = {
|
||||
"complete": template_tunnel_state.get("id") is not None or config.EXTERNAL_TUNNEL_ID,
|
||||
|
|
@ -163,6 +165,7 @@ def status_page():
|
|||
relevant_zone_name_for_tld_policy=relevant_zone_name_for_tld_policy_val,
|
||||
tld_policy_exists=tld_policy_exists_val,
|
||||
account_email_for_tld=account_email_for_tld_val,
|
||||
access_groups=template_access_groups,
|
||||
CF_ZONE_ID_CONFIGURED=bool(config.CF_ZONE_ID)
|
||||
)
|
||||
|
||||
|
|
@ -469,188 +472,141 @@ def ui_add_manual_rule_route():
|
|||
origin_server_name_input = request.form.get('manual_origin_server_name', '').strip()
|
||||
manual_http_host_header = request.form.get('manual_http_host_header', '').strip()
|
||||
|
||||
manual_access_group_id = request.form.get('manual_access_group', '').strip()
|
||||
manual_access_policy_type = request.form.get('manual_access_policy_type', 'none').strip().lower()
|
||||
manual_auth_email = request.form.get('manual_auth_email', '').strip()
|
||||
|
||||
if not domain_name_input or not service_type_input:
|
||||
cloudflared_agent_state["last_action_status"] = "Error: Domain Name and Service Type are required for manual rule."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
if service_type_input not in ["http_status", "bastion"] and not service_address_input:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Service Address is required for type '{service_type_input.upper()}'."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
if manual_access_policy_type == "authenticate_email" and not manual_auth_email:
|
||||
cloudflared_agent_state["last_action_status"] = "Error: Allowed Email(s) required for 'Authenticate by Email' policy."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
if subdomain_input:
|
||||
full_hostname = f"{subdomain_input}.{domain_name_input}"
|
||||
else:
|
||||
full_hostname = domain_name_input
|
||||
|
||||
full_hostname = f"{subdomain_input}.{domain_name_input}" if subdomain_input else domain_name_input
|
||||
if not is_valid_hostname(full_hostname):
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Constructed hostname '{full_hostname}' is invalid."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
processed_path = None
|
||||
if path_input:
|
||||
processed_path = path_input.strip()
|
||||
if not processed_path.startswith('/'):
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Path '{processed_path}' must start with a '/'."
|
||||
return redirect(url_for('web.status_page'))
|
||||
if len(processed_path) > 1 and processed_path.endswith('/'):
|
||||
processed_path = processed_path.rstrip('/')
|
||||
|
||||
key_for_managed_rules = f"{full_hostname}{'|' + processed_path if processed_path else ''}"
|
||||
|
||||
processed_path = f"/{path_input.lstrip('/')}" if path_input else None
|
||||
key_for_managed_rules = get_rule_key(full_hostname, processed_path)
|
||||
|
||||
processed_service_for_cf = ""
|
||||
if service_type_input in ["http", "https"]:
|
||||
if ":" not in service_address_input and "." not in service_address_input and service_address_input != "localhost":
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: For HTTP/S, address '{service_address_input}' should be host:port or a resolvable hostname."
|
||||
return redirect(url_for('web.status_page'))
|
||||
processed_service_for_cf = f"{service_type_input}://{service_address_input}"
|
||||
elif service_type_input in ["tcp", "ssh", "rdp"]:
|
||||
if ":" not in service_address_input:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: For {service_type_input.upper()}, address '{service_address_input}' must be in host:port format."
|
||||
return redirect(url_for('web.status_page'))
|
||||
processed_service_for_cf = f"{service_type_input}://{service_address_input}"
|
||||
elif service_type_input == "http_status":
|
||||
if not service_address_input.isdigit() or not (100 <= int(service_address_input) <= 599):
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Invalid HTTP status code '{service_address_input}'. Must be 100-599."
|
||||
return redirect(url_for('web.status_page'))
|
||||
processed_service_for_cf = f"http_status:{service_address_input}"
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Unsupported service type '{service_type_input}' submitted."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
|
||||
if not is_valid_service(processed_service_for_cf):
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Constructed service string '{processed_service_for_cf}' is invalid."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
target_zone_id = None
|
||||
zone_name_to_lookup = None
|
||||
if zone_name_override_input:
|
||||
zone_name_to_lookup = zone_name_override_input
|
||||
else:
|
||||
parts = domain_name_input.split('.')
|
||||
if len(parts) >= 2:
|
||||
potential_zone = f"{parts[-2]}.{parts[-1]}"
|
||||
zone_name_to_lookup = potential_zone
|
||||
else:
|
||||
zone_name_to_lookup = None
|
||||
|
||||
if zone_name_to_lookup:
|
||||
target_zone_id = get_zone_id_from_name(zone_name_to_lookup)
|
||||
if not target_zone_id and config.CF_ZONE_ID:
|
||||
logging.info(f"Could not find zone for '{zone_name_to_lookup}', trying default CF_ZONE_ID.")
|
||||
target_zone_id = config.CF_ZONE_ID
|
||||
elif not target_zone_id:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Could not find Zone ID for '{zone_name_to_lookup}' and no default CF_ZONE_ID to fallback."
|
||||
return redirect(url_for('web.status_page'))
|
||||
elif config.CF_ZONE_ID:
|
||||
target_zone_id = config.CF_ZONE_ID
|
||||
logging.info(f"Using default CF_ZONE_ID as no specific zone name was provided or derivable.")
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = "Error: Cloudflare Zone Name/ID is required."
|
||||
zone_name_to_lookup = zone_name_override_input or '.'.join(domain_name_input.split('.')[-2:])
|
||||
target_zone_id = get_zone_id_from_name(zone_name_to_lookup) or config.CF_ZONE_ID
|
||||
if not target_zone_id:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Could not determine Zone ID."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
access_app_created_or_updated_id = None
|
||||
access_app_final_config_hash = None
|
||||
cf_access_policies_for_app = []
|
||||
custom_rules_for_hash_str = None
|
||||
desired_session_duration = "24h"
|
||||
desired_app_launcher_visible = False
|
||||
desired_allowed_idps_for_api = None
|
||||
desired_auto_redirect = False
|
||||
desired_app_name = f"DockFlare-{full_hostname}"
|
||||
|
||||
if manual_access_policy_type == "bypass":
|
||||
cf_access_policies_for_app = [{"name": "UI Manual Public Bypass", "decision": "bypass", "include": [{"everyone": {}}]}]
|
||||
custom_rules_for_hash_str = json.dumps(cf_access_policies_for_app)
|
||||
elif manual_access_policy_type == "authenticate_email":
|
||||
cf_access_policies_for_app = [
|
||||
{"name": f"UI Allow Access for {manual_auth_email}", "decision": "allow", "include": [{"email": {"email": manual_auth_email}}]},
|
||||
{"name": "UI Deny Fallback", "decision": "deny", "include": [{"everyone": {}}]}
|
||||
]
|
||||
custom_rules_for_hash_str = json.dumps(cf_access_policies_for_app)
|
||||
|
||||
if manual_access_policy_type in ["bypass", "authenticate_email"]:
|
||||
existing_cf_app = find_cloudflare_access_application_by_hostname(full_hostname)
|
||||
if existing_cf_app and existing_cf_app.get("id"):
|
||||
logging.info(f"Manual Add: Found existing Access App {existing_cf_app.get('id')} for {full_hostname}. Will attempt to update it.")
|
||||
access_app_created_or_updated_id = existing_cf_app.get("id")
|
||||
updated_app = update_cloudflare_access_application(
|
||||
access_app_created_or_updated_id, full_hostname, desired_app_name,
|
||||
desired_session_duration, desired_app_launcher_visible,
|
||||
[full_hostname], cf_access_policies_for_app, desired_allowed_idps_for_api,
|
||||
desired_auto_redirect
|
||||
)
|
||||
if updated_app:
|
||||
access_app_created_or_updated_id = updated_app.get("id")
|
||||
access_app_final_config_hash = generate_access_app_config_hash(
|
||||
manual_access_policy_type, desired_session_duration, desired_app_launcher_visible,
|
||||
desired_allowed_idps_for_api, desired_auto_redirect, custom_access_rules_str=custom_rules_for_hash_str
|
||||
)
|
||||
else:
|
||||
logging.error(f"Failed to update existing Access App for manual rule {full_hostname}")
|
||||
access_app_created_or_updated_id = None
|
||||
else:
|
||||
created_app = create_cloudflare_access_application(
|
||||
full_hostname, desired_app_name,
|
||||
desired_session_duration, desired_app_launcher_visible,
|
||||
[full_hostname], cf_access_policies_for_app,
|
||||
desired_allowed_idps_for_api,
|
||||
desired_auto_redirect
|
||||
)
|
||||
if created_app and created_app.get("id"):
|
||||
access_app_created_or_updated_id = created_app.get("id")
|
||||
access_app_final_config_hash = generate_access_app_config_hash(
|
||||
manual_access_policy_type, desired_session_duration, desired_app_launcher_visible,
|
||||
desired_allowed_idps_for_api, desired_auto_redirect, custom_access_rules_str=custom_rules_for_hash_str
|
||||
)
|
||||
else:
|
||||
logging.error(f"Failed to create Access App for manual rule {full_hostname}")
|
||||
|
||||
access_app_id = None
|
||||
access_policy_type = None
|
||||
access_app_config_hash = None
|
||||
access_group_id = None
|
||||
|
||||
with state_lock:
|
||||
existing_rule_details = managed_rules.get(key_for_managed_rules)
|
||||
if existing_rule_details and existing_rule_details.get("source", "docker") == "docker":
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Rule for {full_hostname} (Path: {processed_path or '(root)'}) is Docker-managed."
|
||||
if manual_access_group_id and manual_access_group_id in access_groups:
|
||||
|
||||
group = access_groups[manual_access_group_id]
|
||||
access_group_id = manual_access_group_id
|
||||
access_policy_type = "group"
|
||||
|
||||
desired_app_name = f"DockFlare-{full_hostname}"
|
||||
desired_session_duration = group.get("session_duration", "24h")
|
||||
desired_app_launcher_visible = group.get("app_launcher_visible", False)
|
||||
desired_allowed_idps = group.get("allowed_idps")
|
||||
desired_auto_redirect = group.get("auto_redirect_to_identity", False)
|
||||
cf_access_policies = group.get("policies")
|
||||
|
||||
access_app_config_hash = generate_access_app_config_hash(
|
||||
policy_type="group", session_duration=desired_session_duration,
|
||||
app_launcher_visible=desired_app_launcher_visible,
|
||||
allowed_idps_str=json.dumps(desired_allowed_idps, sort_keys=True),
|
||||
auto_redirect_to_identity=desired_auto_redirect,
|
||||
custom_access_rules_str=json.dumps(cf_access_policies, sort_keys=True),
|
||||
group_id=access_group_id
|
||||
)
|
||||
|
||||
existing_app = find_cloudflare_access_application_by_hostname(full_hostname)
|
||||
if existing_app:
|
||||
app_result = update_cloudflare_access_application(
|
||||
existing_app['id'], full_hostname, desired_app_name, desired_session_duration,
|
||||
desired_app_launcher_visible, [full_hostname], cf_access_policies,
|
||||
desired_allowed_idps, desired_auto_redirect
|
||||
)
|
||||
else:
|
||||
app_result = create_cloudflare_access_application(
|
||||
full_hostname, desired_app_name, desired_session_duration,
|
||||
desired_app_launcher_visible, [full_hostname], cf_access_policies,
|
||||
desired_allowed_idps, desired_auto_redirect
|
||||
)
|
||||
|
||||
if app_result:
|
||||
access_app_id = app_result.get('id')
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Failed to create/update Access App for group '{access_group_id}'."
|
||||
|
||||
elif manual_access_policy_type and manual_access_policy_type != 'none':
|
||||
|
||||
cf_access_policies = []
|
||||
if manual_access_policy_type == "bypass":
|
||||
cf_access_policies = [{"name": "UI Manual Public Bypass", "decision": "bypass", "include": [{"everyone": {}}]}]
|
||||
elif manual_access_policy_type == "authenticate_email":
|
||||
if not manual_auth_email:
|
||||
cloudflared_agent_state["last_action_status"] = "Error: Email is required for this policy type."
|
||||
return redirect(url_for('web.status_page'))
|
||||
cf_access_policies = [
|
||||
{"name": f"UI Allow Access for {manual_auth_email}", "decision": "allow", "include": [{"email": {"email": manual_auth_email}}]},
|
||||
{"name": "UI Deny Fallback", "decision": "deny", "include": [{"everyone": {}}]}
|
||||
]
|
||||
|
||||
app_result = create_cloudflare_access_application(
|
||||
full_hostname, f"DockFlare-{full_hostname}", "24h", False, [full_hostname], cf_access_policies, None, False
|
||||
)
|
||||
if app_result:
|
||||
access_app_id = app_result.get('id')
|
||||
access_policy_type = manual_access_policy_type
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Failed to create Access App for manual policy."
|
||||
|
||||
with state_lock:
|
||||
if key_for_managed_rules in managed_rules and managed_rules[key_for_managed_rules].get("source") == "docker":
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Rule for {full_hostname} is Docker-managed."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
log_action = "Adding new" if not existing_rule_details else "Updating existing"
|
||||
logging.info(f"{log_action} manual rule for Key: {key_for_managed_rules} (FQDN: {full_hostname}, Path: {processed_path or '(root)'}) with service {processed_service_for_cf}")
|
||||
|
||||
|
||||
managed_rules[key_for_managed_rules] = {
|
||||
"hostname": full_hostname,
|
||||
"service": processed_service_for_cf,
|
||||
"path": processed_path,
|
||||
"hostname_for_dns": full_hostname,
|
||||
"container_id": None,
|
||||
"status": "active",
|
||||
"delete_at": None,
|
||||
"service": processed_service_for_cf,
|
||||
"container_id": None, "status": "active", "delete_at": None,
|
||||
"zone_id": target_zone_id,
|
||||
"no_tls_verify": no_tls_verify,
|
||||
"origin_server_name": origin_server_name_input if origin_server_name_input else None,
|
||||
"http_host_header": manual_http_host_header if manual_http_host_header else None,
|
||||
"access_app_id": access_app_created_or_updated_id if manual_access_policy_type in ["bypass", "authenticate_email"] \
|
||||
else (existing_rule_details.get("access_app_id") if existing_rule_details else None),
|
||||
"access_policy_type": manual_access_policy_type if manual_access_policy_type != "none" else None,
|
||||
"access_app_config_hash": access_app_final_config_hash if manual_access_policy_type in ["bypass", "authenticate_email"] \
|
||||
else (existing_rule_details.get("access_app_config_hash") if existing_rule_details else None),
|
||||
"auth_email": manual_auth_email if manual_access_policy_type == "authenticate_email" else (existing_rule_details.get("auth_email") if existing_rule_details else None),
|
||||
"access_policy_ui_override": True if manual_access_policy_type != "none" else (existing_rule_details.get("access_policy_ui_override", False) if existing_rule_details else False),
|
||||
"source": "manual"
|
||||
"origin_server_name": origin_server_name_input or None,
|
||||
"http_host_header": manual_http_host_header or None,
|
||||
"source": "manual",
|
||||
"access_app_id": access_app_id,
|
||||
"access_policy_type": access_policy_type,
|
||||
"access_app_config_hash": access_app_config_hash,
|
||||
"access_group_id": access_group_id,
|
||||
"access_policy_ui_override": bool(access_app_id)
|
||||
}
|
||||
save_state()
|
||||
|
||||
|
||||
if update_cloudflare_config():
|
||||
if create_cloudflare_dns_record(target_zone_id, full_hostname, effective_tunnel_id):
|
||||
cloudflared_agent_state["last_action_status"] = f"Success: Manual rule for {full_hostname} (Path: {processed_path if processed_path else '(root)'}) added/updated. Policy: {manual_access_policy_type.upper()}."
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = f"Warning: Manual rule for {full_hostname} (Path: {processed_path if processed_path else '(root)'}) added/updated. Policy: {manual_access_policy_type.upper()}. DNS creation FAILED."
|
||||
create_cloudflare_dns_record(target_zone_id, full_hostname, effective_tunnel_id)
|
||||
cloudflared_agent_state["last_action_status"] = f"Success: Manual rule for {full_hostname} added/updated."
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Failed to update Cloudflare tunnel config for manual rule {full_hostname} (Path: {processed_path if processed_path else '(root)'})."
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Failed to update Cloudflare tunnel config."
|
||||
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
|
|
@ -768,17 +724,11 @@ def ui_edit_manual_rule_route():
|
|||
cloudflared_agent_state["last_action_status"] = "Error: Original rule key was missing from the edit request."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
original_rule_details = None
|
||||
with state_lock:
|
||||
original_rule_details = managed_rules.get(original_rule_key)
|
||||
|
||||
if not original_rule_details or original_rule_details.get("source") != "manual":
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Could not find original manual rule '{original_rule_key}' to edit."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
old_zone_id = original_rule_details.get("zone_id")
|
||||
old_access_app_id = original_rule_details.get("access_app_id")
|
||||
old_hostname_for_dns = original_rule_details.get("hostname_for_dns")
|
||||
if not original_rule_details or original_rule_details.get("source") != "manual":
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Could not find original manual rule '{original_rule_key}' to edit."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
subdomain_input = request.form.get('manual_subdomain', '').strip()
|
||||
domain_name_input = request.form.get('manual_domain_name', '').strip()
|
||||
|
|
@ -789,6 +739,7 @@ def ui_edit_manual_rule_route():
|
|||
no_tls_verify = request.form.get('manual_no_tls_verify') == 'on'
|
||||
origin_server_name_input = request.form.get('manual_origin_server_name', '').strip()
|
||||
manual_http_host_header = request.form.get('manual_http_host_header', '').strip()
|
||||
manual_access_group_id = request.form.get('manual_access_group', '').strip()
|
||||
manual_access_policy_type = request.form.get('manual_access_policy_type', 'none').strip().lower()
|
||||
manual_auth_email = request.form.get('manual_auth_email', '').strip()
|
||||
|
||||
|
|
@ -798,27 +749,23 @@ def ui_edit_manual_rule_route():
|
|||
if service_type_input not in ["http_status", "bastion"] and not service_address_input:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Service Address is required for type '{service_type_input.upper()}'."
|
||||
return redirect(url_for('web.status_page'))
|
||||
if manual_access_policy_type == "authenticate_email" and not manual_auth_email:
|
||||
cloudflared_agent_state["last_action_status"] = "Error: Allowed Email(s) required for 'Authenticate by Email' policy."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
full_hostname = f"{subdomain_input}.{domain_name_input}" if subdomain_input else domain_name_input
|
||||
if not is_valid_hostname(full_hostname):
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Constructed hostname '{full_hostname}' is invalid."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
processed_path = path_input.strip() if path_input else None
|
||||
if processed_path and not processed_path.startswith('/'):
|
||||
processed_path = '/' + processed_path
|
||||
|
||||
new_rule_key = f"{full_hostname}{'|' + processed_path if processed_path else ''}"
|
||||
processed_path = f"/{path_input.lstrip('/')}" if path_input else None
|
||||
new_rule_key = get_rule_key(full_hostname, processed_path)
|
||||
|
||||
processed_service_for_cf = ""
|
||||
if service_type_input in ["http", "https", "tcp", "ssh", "rdp"]:
|
||||
if service_type_input in ["http", "https"]:
|
||||
processed_service_for_cf = f"{service_type_input}://{service_address_input}"
|
||||
elif service_type_input in ["tcp", "ssh", "rdp"]:
|
||||
processed_service_for_cf = f"{service_type_input}://{service_address_input}"
|
||||
elif service_type_input == "http_status":
|
||||
processed_service_for_cf = f"http_status:{service_address_input}"
|
||||
|
||||
|
||||
if not is_valid_service(processed_service_for_cf):
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Constructed service string '{processed_service_for_cf}' is invalid."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
|
@ -826,84 +773,125 @@ def ui_edit_manual_rule_route():
|
|||
zone_name_to_lookup = zone_name_override_input or '.'.join(domain_name_input.split('.')[-2:])
|
||||
target_zone_id = get_zone_id_from_name(zone_name_to_lookup) or config.CF_ZONE_ID
|
||||
if not target_zone_id:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Could not determine Zone ID for '{zone_name_to_lookup}'."
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Could not determine Zone ID."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
access_app_created_or_updated_id = None
|
||||
access_app_final_config_hash = None
|
||||
cf_access_policies_for_app = []
|
||||
|
||||
if manual_access_policy_type in ["bypass", "authenticate_email"]:
|
||||
allowed_idps_str_for_hash = None
|
||||
|
||||
if manual_access_policy_type == "bypass":
|
||||
cf_access_policies_for_app = [{"name": "UI Manual Public Bypass", "decision": "bypass", "include": [{"everyone": {}}]}]
|
||||
else:
|
||||
allowed_idps_str_for_hash = "ea94073b-1175-4089-81a2-3498c8c147b3"
|
||||
policy_include_rules = [
|
||||
{"email": {"email": manual_auth_email}},
|
||||
{"login_method": {"id": allowed_idps_str_for_hash}}
|
||||
]
|
||||
cf_access_policies_for_app = [
|
||||
{"name": f"UI Allow Access for {manual_auth_email}", "decision": "allow", "include": policy_include_rules},
|
||||
{"name": "UI Deny Fallback", "decision": "deny", "include": [{"everyone": {}}]}
|
||||
]
|
||||
|
||||
app_id_to_update = old_access_app_id if old_hostname_for_dns == full_hostname else None
|
||||
|
||||
if app_id_to_update:
|
||||
logging.info(f"Manual Edit: Updating existing Access App {app_id_to_update} for {full_hostname}")
|
||||
updated_app = update_cloudflare_access_application(app_id_to_update, full_hostname, f"DockFlare-{full_hostname}", "24h", False, [full_hostname], cf_access_policies_for_app, False)
|
||||
if updated_app: access_app_created_or_updated_id = updated_app.get("id")
|
||||
else:
|
||||
logging.info(f"Manual Edit: Creating new Access App for {full_hostname}")
|
||||
created_app = create_cloudflare_access_application(full_hostname, f"DockFlare-{full_hostname}", "24h", False, [full_hostname], cf_access_policies_for_app, False)
|
||||
if created_app: access_app_created_or_updated_id = created_app.get("id")
|
||||
|
||||
if access_app_created_or_updated_id:
|
||||
access_app_final_config_hash = generate_access_app_config_hash(manual_access_policy_type, "24h", False, allowed_idps_str_for_hash, False, custom_access_rules_str=json.dumps(cf_access_policies_for_app))
|
||||
access_app_id = None
|
||||
access_policy_type = None
|
||||
access_app_config_hash = None
|
||||
access_group_id = None
|
||||
app_to_delete = None
|
||||
|
||||
with state_lock:
|
||||
if new_rule_key != original_rule_key and managed_rules.get(new_rule_key, {}).get("source") == "docker":
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: New rule for {full_hostname} conflicts with an existing Docker-managed rule."
|
||||
if manual_access_group_id and manual_access_group_id in access_groups:
|
||||
group = access_groups[manual_access_group_id]
|
||||
access_group_id = manual_access_group_id
|
||||
access_policy_type = "group"
|
||||
|
||||
desired_app_name = f"DockFlare-{full_hostname}"
|
||||
desired_session_duration = group.get("session_duration", "24h")
|
||||
desired_app_launcher_visible = group.get("app_launcher_visible", False)
|
||||
desired_allowed_idps = group.get("allowed_idps")
|
||||
desired_auto_redirect = group.get("auto_redirect_to_identity", False)
|
||||
cf_access_policies = group.get("policies")
|
||||
|
||||
access_app_config_hash = generate_access_app_config_hash(
|
||||
policy_type="group", session_duration=desired_session_duration,
|
||||
app_launcher_visible=desired_app_launcher_visible,
|
||||
allowed_idps_str=json.dumps(desired_allowed_idps, sort_keys=True),
|
||||
auto_redirect_to_identity=desired_auto_redirect,
|
||||
custom_access_rules_str=json.dumps(cf_access_policies, sort_keys=True),
|
||||
group_id=access_group_id
|
||||
)
|
||||
|
||||
existing_app = find_cloudflare_access_application_by_hostname(full_hostname)
|
||||
app_to_update_id = existing_app['id'] if existing_app else original_rule_details.get('access_app_id')
|
||||
|
||||
if app_to_update_id and (original_rule_details.get('hostname') != full_hostname):
|
||||
app_to_delete = app_to_update_id
|
||||
app_to_update_id = None
|
||||
|
||||
if app_to_update_id:
|
||||
app_result = update_cloudflare_access_application(
|
||||
app_to_update_id, full_hostname, desired_app_name, desired_session_duration,
|
||||
desired_app_launcher_visible, [full_hostname], cf_access_policies,
|
||||
desired_allowed_idps, desired_auto_redirect
|
||||
)
|
||||
else:
|
||||
app_result = create_cloudflare_access_application(
|
||||
full_hostname, desired_app_name, desired_session_duration,
|
||||
desired_app_launcher_visible, [full_hostname], cf_access_policies,
|
||||
desired_allowed_idps, desired_auto_redirect
|
||||
)
|
||||
|
||||
if app_result: access_app_id = app_result.get('id')
|
||||
|
||||
elif manual_access_policy_type and manual_access_policy_type != 'none':
|
||||
cf_access_policies = []
|
||||
if manual_access_policy_type == "bypass":
|
||||
cf_access_policies = [{"name": "UI Manual Public Bypass", "decision": "bypass", "include": [{"everyone": {}}]}]
|
||||
elif manual_access_policy_type == "authenticate_email":
|
||||
if not manual_auth_email:
|
||||
cloudflared_agent_state["last_action_status"] = "Error: Email is required for this policy type."
|
||||
return redirect(url_for('web.status_page'))
|
||||
cf_access_policies = [
|
||||
{"name": f"UI Allow Access for {manual_auth_email}", "decision": "allow", "include": [{"email": {"email": manual_auth_email}}]},
|
||||
{"name": "UI Deny Fallback", "decision": "deny", "include": [{"everyone": {}}]}
|
||||
]
|
||||
|
||||
app_result = create_cloudflare_access_application(
|
||||
full_hostname, f"DockFlare-{full_hostname}", "24h", False, [full_hostname], cf_access_policies, None, False
|
||||
)
|
||||
if app_result:
|
||||
access_app_id = app_result.get('id')
|
||||
access_policy_type = manual_access_policy_type
|
||||
|
||||
else: # Case where policy is set to "None"
|
||||
if original_rule_details.get('access_app_id'):
|
||||
app_to_delete = original_rule_details.get('access_app_id')
|
||||
|
||||
if app_to_delete:
|
||||
delete_cloudflare_access_application(app_to_delete)
|
||||
|
||||
if original_rule_key != new_rule_key:
|
||||
old_hostname = original_rule_details.get('hostname')
|
||||
old_zone_id = original_rule_details.get('zone_id')
|
||||
with state_lock:
|
||||
is_old_hostname_still_used = any(r.get("hostname") == old_hostname for k, r in managed_rules.items() if k != original_rule_key)
|
||||
if not is_old_hostname_still_used:
|
||||
delete_cloudflare_dns_record(old_zone_id, old_hostname, effective_tunnel_id)
|
||||
|
||||
with state_lock:
|
||||
if new_rule_key in managed_rules and new_rule_key != original_rule_key:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: A rule for {full_hostname} already exists."
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
if original_rule_key in managed_rules:
|
||||
del managed_rules[original_rule_key]
|
||||
|
||||
managed_rules[new_rule_key] = {
|
||||
managed_rules[new_rule_key] = {
|
||||
"hostname": full_hostname,
|
||||
"service": processed_service_for_cf, "path": processed_path, "hostname_for_dns": full_hostname,
|
||||
"container_id": None, "status": "active", "delete_at": None, "zone_id": target_zone_id,
|
||||
"no_tls_verify": no_tls_verify, "origin_server_name": origin_server_name_input or None,
|
||||
"http_host_header": manual_http_host_header if manual_http_host_header else None,
|
||||
"access_app_id": access_app_created_or_updated_id, "access_policy_type": manual_access_policy_type if manual_access_policy_type != "none" else None,
|
||||
"access_app_config_hash": access_app_final_config_hash, "auth_email": manual_auth_email if manual_access_policy_type == "authenticate_email" else None,
|
||||
"access_policy_ui_override": True if manual_access_policy_type != "none" else False, "source": "manual"
|
||||
"path": processed_path,
|
||||
"service": processed_service_for_cf,
|
||||
"container_id": None, "status": "active", "delete_at": None,
|
||||
"zone_id": target_zone_id,
|
||||
"no_tls_verify": no_tls_verify,
|
||||
"origin_server_name": origin_server_name_input or None,
|
||||
"http_host_header": manual_http_host_header or None,
|
||||
"source": "manual",
|
||||
"access_app_id": access_app_id,
|
||||
"access_policy_type": access_policy_type,
|
||||
"access_app_config_hash": access_app_config_hash,
|
||||
"access_group_id": access_group_id,
|
||||
"access_policy_ui_override": bool(access_app_id)
|
||||
}
|
||||
save_state()
|
||||
|
||||
if old_hostname_for_dns != full_hostname:
|
||||
with state_lock:
|
||||
is_old_hostname_still_used = any(r.get("hostname_for_dns") == old_hostname_for_dns for r in managed_rules.values())
|
||||
if not is_old_hostname_still_used:
|
||||
logging.info(f"Old hostname '{old_hostname_for_dns}' no longer in use. Deleting its DNS record.")
|
||||
delete_cloudflare_dns_record(old_zone_id, old_hostname_for_dns, effective_tunnel_id)
|
||||
|
||||
if old_access_app_id and old_access_app_id != access_app_created_or_updated_id:
|
||||
with state_lock:
|
||||
is_old_app_id_still_used = any(r.get("access_app_id") == old_access_app_id for r in managed_rules.values())
|
||||
if not is_old_app_id_still_used:
|
||||
logging.info(f"Old Access App ID '{old_access_app_id}' no longer in use. Deleting it.")
|
||||
delete_cloudflare_access_application(old_access_app_id)
|
||||
|
||||
if update_cloudflare_config():
|
||||
if create_cloudflare_dns_record(target_zone_id, full_hostname, effective_tunnel_id):
|
||||
cloudflared_agent_state["last_action_status"] = f"Success: Manual rule for {full_hostname} updated."
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = f"Warning: Manual rule for {full_hostname} updated, but DNS creation failed."
|
||||
create_cloudflare_dns_record(target_zone_id, full_hostname, effective_tunnel_id)
|
||||
cloudflared_agent_state["last_action_status"] = f"Success: Manual rule for {full_hostname} updated."
|
||||
else:
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Failed to update Cloudflare tunnel config for manual rule {full_hostname}."
|
||||
cloudflared_agent_state["last_action_status"] = f"Error: Failed to update Cloudflare tunnel config."
|
||||
|
||||
return redirect(url_for('web.status_page'))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue