feat: Add P2P Domain Conflicts management

Implement comprehensive P2P domain conflict resolution allowing users to choose between local claim hashes and consensus-resolved hashes for domains where they have local claims but another claimant won consensus.

Key features:
- P2P Domain Conflicts UI tab in Local DNS section
- Hash preference toggle (local vs resolved) with automatic client restart
- Extended selector_cache.json to store hashPreferences alongside versionPreferences
- DNS cache invalidation for immediate preference application
- REST API endpoints for conflict detection and preference management
- Automatic Holesail client restart when hash preferences change
- Complete documentation updates across README, API docs, and glossary

Resolves conflicts between local claims and consensus resolution by giving users control over which hash their domain resolves to, with seamless client management ensuring immediate effect.
This commit is contained in:
Raven Scott
2025-12-26 16:36:19 -05:00
parent 480f99ae28
commit 01acfb766c
22 changed files with 1193 additions and 65 deletions
+75 -39
View File
@@ -54,51 +54,87 @@
<div id="local-dns" class="tab-content hidden">
<h2 class="text-2xl font-bold mb-4 flex items-center gap-2">
Custom Local DNS Records
<button onclick="openInfoModal('local-dns')" class="text-sm px-3 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors">Info</button>
Local DNS
</h2>
<div class="mb-6">
<input id="search-local-dns" type="text" placeholder="Search records..." class="w-full p-3 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-primary" oninput="filterLocalDNS()">
<div class="flex gap-2 mb-4">
<button onclick="showSubTab('local-dns', 'records')" id="local-dns-subtab-records" class="px-4 py-2 bg-primary text-white rounded hover:bg-primary-hover">DNS Records</button>
<button onclick="showSubTab('local-dns', 'conflicts')" id="local-dns-subtab-conflicts" class="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-600">DNS Conflicts</button>
<button onclick="showSubTab('local-dns', 'p2p-conflicts')" id="local-dns-subtab-p2p-conflicts" class="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-600">P2P Conflicts</button>
</div>
<div class="overflow-x-auto">
<table class="w-full bg-white dark:bg-gray-800 rounded-lg shadow-md">
<thead class="bg-gray-200 dark:bg-gray-700">
<tr>
<th class="p-3 text-left">Name</th>
<th class="p-3 text-left">Type</th>
<th class="p-3 text-left">Value</th>
<th class="p-3 text-left">TTL</th>
<th class="p-3 text-left">Actions</th>
</tr>
</thead>
<tbody id="localDnsTable"></tbody>
</table>
<!-- DNS Records Sub-tab -->
<div id="local-dns-records" class="sub-tab-content">
<div class="mb-4 flex items-center gap-2">
<h3 class="text-xl font-bold">Custom Local DNS Records</h3>
<button onclick="openInfoModal('local-dns')" class="text-sm px-3 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors">Info</button>
</div>
<div class="mb-6">
<input id="search-local-dns" type="text" placeholder="Search records..." class="w-full p-3 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-primary" oninput="filterLocalDNS()">
</div>
<div class="overflow-x-auto">
<table class="w-full bg-white dark:bg-gray-800 rounded-lg shadow-md">
<thead class="bg-gray-200 dark:bg-gray-700">
<tr>
<th class="p-3 text-left">Name</th>
<th class="p-3 text-left">Type</th>
<th class="p-3 text-left">Value</th>
<th class="p-3 text-left">TTL</th>
<th class="p-3 text-left">Actions</th>
</tr>
</thead>
<tbody id="localDnsTable"></tbody>
</table>
</div>
<div id="localDnsPagination" class="flex justify-center mt-4 space-x-2"></div>
<button onclick="openLocalDnsModal()" class="mt-4 px-4 py-2 bg-primary text-white rounded hover:bg-primary-hover">Add Record</button>
</div>
<div id="localDnsPagination" class="flex justify-center mt-4 space-x-2"></div>
<button onclick="openLocalDnsModal()" class="mt-4 px-4 py-2 bg-primary text-white rounded hover:bg-primary-hover">Add Record</button>
<h2 class="text-2xl font-bold mt-8 mb-4 flex items-center gap-2">
DNS Conflict Selector
<button onclick="openInfoModal('dns-conflicts')" class="text-sm px-3 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors">Info</button>
</h2>
<div class="mb-6">
<input id="search-dns-conflicts" type="text" placeholder="Search conflicts..." class="w-full p-3 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-primary" oninput="filterDnsConflicts()">
<!-- DNS Conflicts Sub-tab -->
<div id="local-dns-conflicts" class="sub-tab-content hidden">
<div class="mb-6">
<input id="search-dns-conflicts" type="text" placeholder="Search conflicts..." class="w-full p-3 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-primary" oninput="filterDnsConflicts()">
</div>
<div class="overflow-x-auto">
<table class="w-full bg-white dark:bg-gray-800 rounded-lg shadow-md">
<thead class="bg-gray-200 dark:bg-gray-700">
<tr>
<th class="p-3 text-left">Domain</th>
<th class="p-3 text-left">Public IP</th>
<th class="p-3 text-left">Mode</th>
</tr>
</thead>
<tbody id="dnsConflictsTable"></tbody>
</table>
</div>
<div id="dnsConflictsPagination" class="flex justify-center mt-4 space-x-2"></div>
</div>
<div class="overflow-x-auto">
<table class="w-full bg-white dark:bg-gray-800 rounded-lg shadow-md">
<thead class="bg-gray-200 dark:bg-gray-700">
<tr>
<th class="p-3 text-left">Domain</th>
<th class="p-3 text-left">Public IP</th>
<th class="p-3 text-left">Mode</th>
</tr>
</thead>
<tbody id="dnsConflictsTable"></tbody>
</table>
<!-- P2P Domain Conflicts Sub-tab -->
<div id="local-dns-p2p-conflicts" class="sub-tab-content hidden">
<div class="mb-4 flex items-center gap-2">
<h3 class="text-xl font-bold">P2P Domain Conflicts</h3>
<button onclick="openInfoModal('p2p-domain-conflicts')" class="text-sm px-3 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors">Info</button>
</div>
<div class="mb-6">
<input id="search-p2p-domain-conflicts" type="text" placeholder="Search conflicts..." class="w-full p-3 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-primary" oninput="filterP2pDomainConflicts()">
</div>
<div class="overflow-x-auto">
<table class="w-full bg-white dark:bg-gray-800 rounded-lg shadow-md">
<thead class="bg-gray-200 dark:bg-gray-700">
<tr>
<th class="p-3 text-left">Domain</th>
<th class="p-3 text-left">Local Hash</th>
<th class="p-3 text-left">Resolved Hash</th>
<th class="p-3 text-left">Hash Preference</th>
</tr>
</thead>
<tbody id="p2pDomainConflictsTable"></tbody>
</table>
</div>
<div id="p2pDomainConflictsPagination" class="flex justify-center mt-4 space-x-2"></div>
</div>
<div id="dnsConflictsPagination" class="flex justify-center mt-4 space-x-2"></div>
</div>
<div id="entries" class="tab-content hidden">
<h2 class="text-2xl font-bold mb-4 flex items-center gap-2">
Autopass Entries