Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eefb0e427e | ||
|
|
c23d81b740 |
134
api/button.html
Normal file
134
api/button.html
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Embedded NOSTR_LOGIN_LITE</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 40px;
|
||||||
|
background: white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 90vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 400px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-button {
|
||||||
|
background: #0066cc;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-button:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div id="login-button">Login</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../lite/nostr.bundle.js"></script>
|
||||||
|
<script src="../lite/nostr-lite.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let isAuthenticated = false;
|
||||||
|
let currentUser = null;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
await window.NOSTR_LOGIN_LITE.init({
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
extension: true,
|
||||||
|
local: true,
|
||||||
|
readonly: true,
|
||||||
|
connect: true,
|
||||||
|
remote: true,
|
||||||
|
otp: true
|
||||||
|
},
|
||||||
|
floatingTab: {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen for authentication events
|
||||||
|
window.addEventListener('nlMethodSelected', handleAuthEvent);
|
||||||
|
window.addEventListener('nlLogout', handleLogoutEvent);
|
||||||
|
|
||||||
|
// Check for existing authentication state
|
||||||
|
checkAuthState();
|
||||||
|
|
||||||
|
// Initialize button
|
||||||
|
updateButtonState();
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleAuthEvent(event) {
|
||||||
|
const { pubkey, method } = event.detail;
|
||||||
|
console.log(`Authenticated with ${method}, pubkey: ${pubkey}`);
|
||||||
|
|
||||||
|
isAuthenticated = true;
|
||||||
|
currentUser = event.detail;
|
||||||
|
updateButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLogoutEvent() {
|
||||||
|
console.log('Logout event received');
|
||||||
|
|
||||||
|
isAuthenticated = false;
|
||||||
|
currentUser = null;
|
||||||
|
updateButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkAuthState() {
|
||||||
|
// Check if user is already authenticated (from persistent storage)
|
||||||
|
try {
|
||||||
|
// Try to get public key - this will work if already authenticated
|
||||||
|
window.nostr.getPublicKey().then(pubkey => {
|
||||||
|
console.log('Found existing authentication, pubkey:', pubkey);
|
||||||
|
isAuthenticated = true;
|
||||||
|
currentUser = { pubkey, method: 'persistent' };
|
||||||
|
updateButtonState();
|
||||||
|
}).catch(error => {
|
||||||
|
console.log('No existing authentication found:', error.message);
|
||||||
|
// User is not authenticated, button stays in login state
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log('No existing authentication found');
|
||||||
|
// User is not authenticated, button stays in login state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateButtonState() {
|
||||||
|
const button = document.getElementById('login-button');
|
||||||
|
|
||||||
|
if (isAuthenticated) {
|
||||||
|
button.textContent = 'Logout';
|
||||||
|
button.onclick = () => window.NOSTR_LOGIN_LITE.logout();
|
||||||
|
button.style.background = '#dc3545'; // Red for logout
|
||||||
|
} else {
|
||||||
|
button.textContent = 'Login';
|
||||||
|
button.onclick = () => window.NOSTR_LOGIN_LITE.launch('login');
|
||||||
|
button.style.background = '#0066cc'; // Blue for login
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
596
api/index.html
596
api/index.html
@@ -169,10 +169,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.config-table {
|
.config-table {
|
||||||
border: var(--border-width) solid var(--primary-color);
|
border: 1px solid var(--primary-color);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -183,6 +184,12 @@
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-family: var(--font-family);
|
font-family: var(--font-family);
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-table-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-table th {
|
.config-table th {
|
||||||
@@ -243,6 +250,53 @@
|
|||||||
background-color: var(--secondary-color);
|
background-color: var(--secondary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-info-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-details {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-logout-btn {
|
||||||
|
width: auto;
|
||||||
|
min-width: 120px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--secondary-color);
|
||||||
|
color: var(--primary-color);
|
||||||
|
border: var(--border-width) solid var(--primary-color);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
font-family: var(--font-family);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
margin: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-logout-btn:hover {
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-logout-btn:active {
|
||||||
|
background: var(--accent-color);
|
||||||
|
color: var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-logout-btn.logout-state {
|
||||||
|
background: var(--accent-color);
|
||||||
|
color: var(--secondary-color);
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-logout-btn.logout-state:hover {
|
||||||
|
background: var(--primary-color);
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
.user-pubkey {
|
.user-pubkey {
|
||||||
font-family: var(--font-family);
|
font-family: var(--font-family);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -378,7 +432,20 @@
|
|||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
/* Main Sections Wrapper */
|
||||||
|
.main-sections-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--border-width);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-section {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
body {
|
body {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
@@ -401,182 +468,199 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>C-RELAY ADMIN API</h1>
|
<h1>C-RELAY ADMIN API</h1>
|
||||||
|
|
||||||
<!-- Login Section -->
|
<!-- Main Sections Wrapper -->
|
||||||
<div id="login-section">
|
<div class="main-sections-wrapper">
|
||||||
<div class="section">
|
|
||||||
<h2>NOSTR AUTHENTICATION</h2>
|
|
||||||
<p>Please login with your Nostr identity to access the admin interface.</p>
|
|
||||||
<!-- nostr-lite login UI will be injected here -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Main Interface (hidden until logged in) -->
|
<!-- Persistent Authentication Header - Always Visible -->
|
||||||
<div id="main-interface" class="hidden">
|
<div id="persistent-auth-container" class="section flex-section">
|
||||||
|
<div class="user-info-container">
|
||||||
<!-- User Info Section - At the top of main interface -->
|
<button type="button" id="login-logout-btn" class="login-logout-btn">LOGIN</button>
|
||||||
<div class="section">
|
<div class="user-details" id="persistent-user-details" style="display: none;">
|
||||||
<h2>LOGGED IN USER</h2>
|
<div><strong>Name:</strong> <span id="persistent-user-name">Loading...</span></div>
|
||||||
<div class="user-info">
|
<div><strong>Public Key:</strong>
|
||||||
<div><strong>Name:</strong> <span id="user-name">Loading...</span></div>
|
<div class="user-pubkey" id="persistent-user-pubkey">Loading...</div>
|
||||||
<div><strong>Public Key:</strong>
|
</div>
|
||||||
<div class="user-pubkey" id="user-pubkey">Loading...</div>
|
<div><strong>About:</strong> <span id="persistent-user-about">Loading...</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div><strong>About:</strong> <span id="user-about">Loading...</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
<button type="button" id="logout-btn">LOGOUT</button>
|
</div>
|
||||||
|
|
||||||
|
<!-- Login Section -->
|
||||||
|
<div id="login-section" class="flex-section">
|
||||||
|
<div class="section">
|
||||||
|
<h2>NOSTR AUTHENTICATION</h2>
|
||||||
|
<p id="login-instructions">Please login with your Nostr identity to access the admin interface.</p>
|
||||||
|
<!-- nostr-lite login UI will be injected here -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Relay Connection Section -->
|
<!-- Relay Connection Section -->
|
||||||
<div class="section">
|
<div id="relay-connection-section" class="flex-section">
|
||||||
|
<div class="section">
|
||||||
|
<h2>RELAY CONNECTION</h2>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label for="relay-connection-url">Relay URL:</label>
|
<label for="relay-connection-url">Relay URL:</label>
|
||||||
<input type="text" id="relay-connection-url" value="ws://localhost:8888" placeholder="ws://localhost:8888 or wss://relay.example.com">
|
<input type="text" id="relay-connection-url" value="ws://localhost:8888"
|
||||||
|
placeholder="ws://localhost:8888 or wss://relay.example.com">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="relay-pubkey-manual">Relay Pubkey (if not available via NIP-11):</label>
|
||||||
|
<input type="text" id="relay-pubkey-manual" placeholder="64-character hex pubkey"
|
||||||
|
pattern="[0-9a-fA-F]{64}" title="64-character hexadecimal public key">
|
||||||
|
<small>If the relay hasn't been configured yet, enter the relay pubkey shown during startup</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="inline-buttons">
|
||||||
|
<button type="button" id="connect-relay-btn">CONNECT TO RELAY</button>
|
||||||
|
<button type="button" id="disconnect-relay-btn" disabled>DISCONNECT</button>
|
||||||
|
<button type="button" id="test-websocket-btn" disabled>TEST WEBSOCKET</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status disconnected" id="relay-connection-status">NOT CONNECTED</div>
|
||||||
|
|
||||||
|
<!-- Relay Information Display -->
|
||||||
|
<div id="relay-info-display" class="hidden">
|
||||||
|
<h3>Relay Information (NIP-11)</h3>
|
||||||
|
<table class="config-table" id="relay-info-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Property</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="relay-info-table-body">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-group">
|
|
||||||
<label for="relay-pubkey-manual">Relay Pubkey (if not available via NIP-11):</label>
|
|
||||||
<input type="text" id="relay-pubkey-manual" placeholder="64-character hex pubkey" pattern="[0-9a-fA-F]{64}" title="64-character hexadecimal public key">
|
|
||||||
<small>If the relay hasn't been configured yet, enter the relay pubkey shown during startup</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="inline-buttons">
|
|
||||||
<button type="button" id="connect-relay-btn">CONNECT TO RELAY</button>
|
|
||||||
<button type="button" id="disconnect-relay-btn" disabled>DISCONNECT</button>
|
|
||||||
<button type="button" id="test-websocket-btn" disabled>TEST WEBSOCKET</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status disconnected" id="relay-connection-status">NOT CONNECTED</div>
|
|
||||||
|
|
||||||
<!-- Relay Information Display -->
|
</div> <!-- End Main Sections Wrapper -->
|
||||||
<div id="relay-info-display" class="hidden">
|
|
||||||
<h3>Relay Information (NIP-11)</h3>
|
|
||||||
<table class="config-table" id="relay-info-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
<!-- Testing Section -->
|
||||||
<th>Property</th>
|
<div id="div_config" class="section flex-section">
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
<div id="config-display" class="hidden">
|
||||||
</thead>
|
<div id="config-view-mode">
|
||||||
<tbody id="relay-info-table-body">
|
<div class="config-table-container">
|
||||||
</tbody>
|
<table class="config-table" id="config-table">
|
||||||
</table>
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Parameter</th>
|
||||||
|
<th>Value</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="config-table-body">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="inline-buttons">
|
||||||
|
<button type="button" id="fetch-config-btn">REFRESH</button>
|
||||||
|
<button type="button" id="edit-config-btn">EDIT CONFIGURATION</button>
|
||||||
|
<button type="button" id="copy-config-btn">COPY CONFIGURATION</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="config-edit-mode" class="hidden">
|
||||||
|
<h3>Edit Configuration</h3>
|
||||||
|
<div id="config-form" class="section">
|
||||||
|
<!-- Dynamic form will be generated here -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="inline-buttons">
|
||||||
|
<button type="button" id="save-config-btn">SAVE & PUBLISH</button>
|
||||||
|
<button type="button" id="cancel-edit-btn">CANCEL</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<!-- Auth Rules Management - Moved after configuration -->
|
||||||
|
<div class="section flex-section" id="authRulesSection" style="display: none;">
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>AUTH RULES MANAGEMENT</h2>
|
||||||
|
<div class="status" id="authRulesStatus">●</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Testing Section - Always Visible -->
|
<div class="auth-rules-controls">
|
||||||
<div class="section">
|
<div class="inline-buttons">
|
||||||
|
<button id="viewAuthRulesBtn" class="btn">VIEW RULES</button>
|
||||||
|
<button id="refreshAuthRulesBtn" class="btn">REFRESH</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="status disconnected" id="relay-status">READY TO FETCH</div>
|
<!-- Auth Rules Table -->
|
||||||
<div class="inline-buttons">
|
<div id="authRulesTableContainer" style="display: none;">
|
||||||
<button type="button" id="fetch-config-btn">FETCH CONFIGURATION (REQUIRES LOGIN + RELAY CONNECTION)</button>
|
<table class="config-table" id="authRulesTable">
|
||||||
</div>
|
|
||||||
<div class="status disconnected" id="config-status">NO CONFIGURATION LOADED</div>
|
|
||||||
|
|
||||||
<div id="config-display" class="hidden">
|
|
||||||
<div id="config-view-mode">
|
|
||||||
<table class="config-table" id="config-table">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Parameter</th>
|
<th>Rule Type</th>
|
||||||
<th>Value</th>
|
<th>Pattern Type</th>
|
||||||
|
<th>Pattern Value</th>
|
||||||
|
<th>Action</th>
|
||||||
|
<th>Status</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="config-table-body">
|
<tbody id="authRulesTableBody">
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="inline-buttons">
|
|
||||||
<button type="button" id="edit-config-btn">EDIT CONFIGURATION</button>
|
|
||||||
<button type="button" id="copy-config-btn">COPY CONFIGURATION</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="config-edit-mode" class="hidden">
|
<!-- Simplified Auth Rule Input Section -->
|
||||||
<h3>Edit Configuration</h3>
|
<div id="authRuleInputSections" style="display: block;">
|
||||||
<div id="config-form" class="section">
|
|
||||||
<!-- Dynamic form will be generated here -->
|
<!-- Combined Pubkey Auth Rule Section -->
|
||||||
|
<div class="auth-rule-section">
|
||||||
|
<h3>MANAGE PUBKEY ACCESS</h3>
|
||||||
|
<p>Add pubkeys to whitelist (allow) or blacklist (deny) access</p>
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="authRulePubkey">Pubkey (nsec or hex):</label>
|
||||||
|
<input type="text" id="authRulePubkey" placeholder="nsec1... or 64-character hex pubkey">
|
||||||
|
<small id="authRuleHelp">Enter nsec (will auto-convert) or 64-character hex pubkey</small>
|
||||||
|
</div>
|
||||||
|
<div id="whitelistWarning" class="warning-box" style="display: none;">
|
||||||
|
<strong>⚠️ WARNING:</strong> Adding whitelist rules changes relay behavior to whitelist-only
|
||||||
|
mode.
|
||||||
|
Only whitelisted users will be able to interact with the relay.
|
||||||
|
</div>
|
||||||
|
<div class="inline-buttons">
|
||||||
|
<button type="button" id="addWhitelistBtn" onclick="addWhitelistRule()">ADD TO
|
||||||
|
WHITELIST</button>
|
||||||
|
<button type="button" id="addBlacklistBtn" onclick="addBlacklistRule()">ADD TO
|
||||||
|
BLACKLIST</button>
|
||||||
|
</div>
|
||||||
|
<div id="authRuleStatus" class="rule-status"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inline-buttons">
|
|
||||||
<button type="button" id="save-config-btn">SAVE & PUBLISH</button>
|
|
||||||
<button type="button" id="cancel-edit-btn">CANCEL</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<!-- Auth Rules Status Display -->
|
||||||
</div>
|
<div id="authRulesStatusDisplay" style="display: none;">
|
||||||
|
<h3>Auth System Status</h3>
|
||||||
<!-- Auth Rules Management - Moved after configuration -->
|
<div class="status" id="authSystemStatus">CHECKING...</div>
|
||||||
<div class="section" id="authRulesSection" style="display: none;">
|
<div class="json-display" id="authRulesCount">
|
||||||
<div class="section-header">
|
Rules: Loading...
|
||||||
<h2>AUTH RULES MANAGEMENT</h2>
|
</div>
|
||||||
<div class="status" id="authRulesStatus">●</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="auth-rules-controls">
|
|
||||||
<div class="inline-buttons">
|
|
||||||
<button id="viewAuthRulesBtn" class="btn">VIEW RULES</button>
|
|
||||||
<button id="refreshAuthRulesBtn" class="btn">REFRESH</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Auth Rules Table -->
|
|
||||||
<div id="authRulesTableContainer" style="display: none;">
|
|
||||||
<table class="config-table" id="authRulesTable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Rule Type</th>
|
|
||||||
<th>Pattern Type</th>
|
|
||||||
<th>Pattern Value</th>
|
|
||||||
<th>Action</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="authRulesTableBody">
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Simplified Auth Rule Input Section -->
|
|
||||||
<div id="authRuleInputSections" style="display: block;">
|
|
||||||
|
|
||||||
<!-- Combined Pubkey Auth Rule Section -->
|
|
||||||
<div class="auth-rule-section">
|
|
||||||
<h3>MANAGE PUBKEY ACCESS</h3>
|
|
||||||
<p>Add pubkeys to whitelist (allow) or blacklist (deny) access</p>
|
|
||||||
<div class="input-group">
|
|
||||||
<label for="authRulePubkey">Pubkey (nsec or hex):</label>
|
|
||||||
<input type="text" id="authRulePubkey" placeholder="nsec1... or 64-character hex pubkey">
|
|
||||||
<small id="authRuleHelp">Enter nsec (will auto-convert) or 64-character hex pubkey</small>
|
|
||||||
</div>
|
|
||||||
<div id="whitelistWarning" class="warning-box" style="display: none;">
|
|
||||||
<strong>⚠️ WARNING:</strong> Adding whitelist rules changes relay behavior to whitelist-only mode.
|
|
||||||
Only whitelisted users will be able to interact with the relay.
|
|
||||||
</div>
|
|
||||||
<div class="inline-buttons">
|
|
||||||
<button type="button" id="addWhitelistBtn" onclick="addWhitelistRule()">ADD TO WHITELIST</button>
|
|
||||||
<button type="button" id="addBlacklistBtn" onclick="addBlacklistRule()">ADD TO BLACKLIST</button>
|
|
||||||
</div>
|
|
||||||
<div id="authRuleStatus" class="rule-status"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Auth Rules Status Display -->
|
|
||||||
<div id="authRulesStatusDisplay" style="display: none;">
|
|
||||||
<h3>Auth System Status</h3>
|
|
||||||
<div class="status" id="authSystemStatus">CHECKING...</div>
|
|
||||||
<div class="json-display" id="authRulesCount">
|
|
||||||
Rules: Loading...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- TESTS Section -->
|
<!-- TESTS Section -->
|
||||||
<div class="section">
|
<div class="section">
|
||||||
@@ -588,7 +672,8 @@
|
|||||||
<label for="test-event-log">Event Log (Sent/Received):</label>
|
<label for="test-event-log">Event Log (Sent/Received):</label>
|
||||||
<div class="log-panel" id="test-event-log" style="height: 300px;">
|
<div class="log-panel" id="test-event-log" style="height: 300px;">
|
||||||
<div class="log-entry">
|
<div class="log-entry">
|
||||||
<span class="log-timestamp">SYSTEM:</span> Test interface ready. Click buttons below to test admin API functions.
|
<span class="log-timestamp">SYSTEM:</span> Test interface ready. Click buttons below to test admin
|
||||||
|
API functions.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" id="clear-test-log-btn">CLEAR TEST LOG</button>
|
<button type="button" id="clear-test-log-btn">CLEAR TEST LOG</button>
|
||||||
@@ -616,8 +701,10 @@
|
|||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label for="test-pubkey-input">Test Pubkey (for blacklist/whitelist):</label>
|
<label for="test-pubkey-input">Test Pubkey (for blacklist/whitelist):</label>
|
||||||
<div style="display: flex; gap: 10px; align-items: flex-start;">
|
<div style="display: flex; gap: 10px; align-items: flex-start;">
|
||||||
<input type="text" id="test-pubkey-input" placeholder="Enter pubkey or nsec1... for testing" style="flex: 1;">
|
<input type="text" id="test-pubkey-input" placeholder="Enter pubkey or nsec1... for testing"
|
||||||
<button type="button" id="generate-test-key-btn" style="width: auto; padding: 8px 16px; white-space: nowrap;">GENERATE KEY</button>
|
style="flex: 1;">
|
||||||
|
<button type="button" id="generate-test-key-btn"
|
||||||
|
style="width: auto; padding: 8px 16px; white-space: nowrap;">GENERATE KEY</button>
|
||||||
</div>
|
</div>
|
||||||
<small>This pubkey will be used for blacklist/whitelist tests</small>
|
<small>This pubkey will be used for blacklist/whitelist tests</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -674,13 +761,12 @@
|
|||||||
|
|
||||||
// DOM elements
|
// DOM elements
|
||||||
const loginSection = document.getElementById('login-section');
|
const loginSection = document.getElementById('login-section');
|
||||||
const mainInterface = document.getElementById('main-interface');
|
// const mainInterface = document.getElementById('main-interface');
|
||||||
const userName = document.getElementById('user-name');
|
const persistentUserName = document.getElementById('persistent-user-name');
|
||||||
const userPubkeyDisplay = document.getElementById('user-pubkey');
|
const persistentUserPubkey = document.getElementById('persistent-user-pubkey');
|
||||||
const userAbout = document.getElementById('user-about');
|
const persistentUserAbout = document.getElementById('persistent-user-about');
|
||||||
const logoutBtn = document.getElementById('logout-btn');
|
const persistentUserDetails = document.getElementById('persistent-user-details');
|
||||||
const relayUrl = document.getElementById('relay-url');
|
const relayUrl = document.getElementById('relay-url');
|
||||||
const relayStatus = document.getElementById('relay-status');
|
|
||||||
const fetchConfigBtn = document.getElementById('fetch-config-btn');
|
const fetchConfigBtn = document.getElementById('fetch-config-btn');
|
||||||
// Relay connection elements
|
// Relay connection elements
|
||||||
const relayConnectionUrl = document.getElementById('relay-connection-url');
|
const relayConnectionUrl = document.getElementById('relay-connection-url');
|
||||||
@@ -689,7 +775,6 @@
|
|||||||
const connectRelayBtn = document.getElementById('connect-relay-btn');
|
const connectRelayBtn = document.getElementById('connect-relay-btn');
|
||||||
const disconnectRelayBtn = document.getElementById('disconnect-relay-btn');
|
const disconnectRelayBtn = document.getElementById('disconnect-relay-btn');
|
||||||
const testWebSocketBtn = document.getElementById('test-websocket-btn');
|
const testWebSocketBtn = document.getElementById('test-websocket-btn');
|
||||||
const configStatus = document.getElementById('config-status');
|
|
||||||
const configDisplay = document.getElementById('config-display');
|
const configDisplay = document.getElementById('config-display');
|
||||||
const configViewMode = document.getElementById('config-view-mode');
|
const configViewMode = document.getElementById('config-view-mode');
|
||||||
const configEditMode = document.getElementById('config-edit-mode');
|
const configEditMode = document.getElementById('config-edit-mode');
|
||||||
@@ -1106,6 +1191,7 @@
|
|||||||
// Show main interface
|
// Show main interface
|
||||||
showMainInterface();
|
showMainInterface();
|
||||||
loadUserProfile();
|
loadUserProfile();
|
||||||
|
updateLoginLogoutButton();
|
||||||
|
|
||||||
// Note: Configuration fetching now requires explicit relay connection
|
// Note: Configuration fetching now requires explicit relay connection
|
||||||
// User must connect to relay manually after login
|
// User must connect to relay manually after login
|
||||||
@@ -1131,25 +1217,25 @@
|
|||||||
readonly: true,
|
readonly: true,
|
||||||
connect: true,
|
connect: true,
|
||||||
remote: true,
|
remote: true,
|
||||||
otp: true
|
otp: false
|
||||||
},
|
},
|
||||||
floatingTab: {
|
floatingTab: {
|
||||||
enabled: true,
|
enabled: false,
|
||||||
hPosition: 1, // 0.0-1.0 or '95%' from left
|
// hPosition: 1, // 0.0-1.0 or '95%' from left
|
||||||
vPosition: 0, // 0.0-1.0 or '50%' from top
|
// vPosition: 0, // 0.0-1.0 or '50%' from top
|
||||||
appearance: {
|
// appearance: {
|
||||||
style: 'square', // 'pill', 'square', 'circle', 'minimal'
|
// style: 'square', // 'pill', 'square', 'circle', 'minimal'
|
||||||
// icon: '[LOGIN]', // Now uses text-based icons like [LOGIN], [KEY], [NET]
|
// // icon: '[LOGIN]', // Now uses text-based icons like [LOGIN], [KEY], [NET]
|
||||||
text: 'Login'
|
// text: 'Login'
|
||||||
},
|
// },
|
||||||
behavior: {
|
// behavior: {
|
||||||
hideWhenAuthenticated: false,
|
// hideWhenAuthenticated: false,
|
||||||
showUserInfo: true,
|
// showUserInfo: true,
|
||||||
autoSlide: true
|
// autoSlide: true
|
||||||
},
|
// },
|
||||||
animation: {
|
// animation: {
|
||||||
slideDirection: 'auto' // 'auto', 'left', 'right', 'up', 'down'
|
// slideDirection: 'auto' // 'auto', 'left', 'right', 'up', 'down'
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1167,6 +1253,7 @@
|
|||||||
|
|
||||||
// Listen for authentication events
|
// Listen for authentication events
|
||||||
window.addEventListener('nlMethodSelected', handleAuthEvent);
|
window.addEventListener('nlMethodSelected', handleAuthEvent);
|
||||||
|
window.addEventListener('nlLogout', handleLogoutEvent);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Failed to initialize Nostr login: ' + error.message);
|
console.log('Failed to initialize Nostr login: ' + error.message);
|
||||||
@@ -1185,6 +1272,7 @@
|
|||||||
|
|
||||||
showMainInterface();
|
showMainInterface();
|
||||||
loadUserProfile();
|
loadUserProfile();
|
||||||
|
updateLoginLogoutButton();
|
||||||
|
|
||||||
// Note: Configuration fetching now requires explicit relay connection
|
// Note: Configuration fetching now requires explicit relay connection
|
||||||
// User must connect to relay manually after login
|
// User must connect to relay manually after login
|
||||||
@@ -1195,11 +1283,45 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle logout events
|
||||||
|
function handleLogoutEvent() {
|
||||||
|
console.log('Logout event received');
|
||||||
|
|
||||||
|
userPubkey = null;
|
||||||
|
isLoggedIn = false;
|
||||||
|
currentConfig = null;
|
||||||
|
|
||||||
|
// Clean up relay connection
|
||||||
|
disconnectFromRelay();
|
||||||
|
|
||||||
|
// Reset UI
|
||||||
|
// mainInterface.classList.add('hidden');
|
||||||
|
loginSection.classList.remove('hidden');
|
||||||
|
updateConfigStatus(false);
|
||||||
|
updateLoginLogoutButton();
|
||||||
|
hideAuthRulesSection();
|
||||||
|
|
||||||
|
console.log('Logout event handled successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect from relay and clean up connections
|
||||||
|
function disconnectFromRelay() {
|
||||||
|
if (relayPool) {
|
||||||
|
console.log('Cleaning up relay pool connection...');
|
||||||
|
const url = relayUrl.value.trim();
|
||||||
|
if (url) {
|
||||||
|
relayPool.close([url]);
|
||||||
|
}
|
||||||
|
relayPool = null;
|
||||||
|
subscriptionId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Show main interface after login
|
// Show main interface after login
|
||||||
function showMainInterface() {
|
function showMainInterface() {
|
||||||
loginSection.classList.add('hidden');
|
loginSection.classList.add('hidden');
|
||||||
mainInterface.classList.remove('hidden');
|
// mainInterface.classList.remove('hidden');
|
||||||
userPubkeyDisplay.textContent = userPubkey;
|
updateLoginLogoutButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load user profile using nostr-tools pool
|
// Load user profile using nostr-tools pool
|
||||||
@@ -1207,8 +1329,8 @@
|
|||||||
if (!userPubkey) return;
|
if (!userPubkey) return;
|
||||||
|
|
||||||
console.log('Loading user profile...');
|
console.log('Loading user profile...');
|
||||||
userName.textContent = 'Loading...';
|
persistentUserName.textContent = 'Loading...';
|
||||||
userAbout.textContent = 'Loading...';
|
persistentUserAbout.textContent = 'Loading...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create a SimplePool instance for profile loading
|
// Create a SimplePool instance for profile loading
|
||||||
@@ -1223,11 +1345,16 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (events.length > 0) {
|
if (events.length > 0) {
|
||||||
|
console.log('Profile event found:', events[0]);
|
||||||
const profile = JSON.parse(events[0].content);
|
const profile = JSON.parse(events[0].content);
|
||||||
|
console.log('Parsed profile:', profile);
|
||||||
displayProfile(profile);
|
displayProfile(profile);
|
||||||
} else {
|
} else {
|
||||||
userName.textContent = 'Anonymous User';
|
console.log('No profile events found for pubkey:', userPubkey);
|
||||||
userAbout.textContent = 'No profile found';
|
persistentUserName.textContent = 'Anonymous User';
|
||||||
|
persistentUserAbout.textContent = 'No profile found';
|
||||||
|
// Still show the pubkey since we have it
|
||||||
|
persistentUserPubkey.textContent = userPubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the profile pool
|
// Close the profile pool
|
||||||
@@ -1235,8 +1362,10 @@
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Profile loading failed: ' + error.message);
|
console.log('Profile loading failed: ' + error.message);
|
||||||
userName.textContent = 'Error loading profile';
|
persistentUserName.textContent = 'Error loading profile';
|
||||||
userAbout.textContent = error.message;
|
persistentUserAbout.textContent = error.message;
|
||||||
|
// Still show the pubkey since we have it
|
||||||
|
persistentUserPubkey.textContent = userPubkey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,10 +1374,12 @@
|
|||||||
const name = profile.name || profile.display_name || profile.displayName || 'Anonymous User';
|
const name = profile.name || profile.display_name || profile.displayName || 'Anonymous User';
|
||||||
const about = profile.about || 'No description provided';
|
const about = profile.about || 'No description provided';
|
||||||
|
|
||||||
userName.textContent = name;
|
// Update persistent user details
|
||||||
userAbout.textContent = about;
|
persistentUserName.textContent = name;
|
||||||
|
persistentUserPubkey.textContent = userPubkey;
|
||||||
|
persistentUserAbout.textContent = about;
|
||||||
|
|
||||||
console.log(`Profile loaded for: ${name}`);
|
console.log(`Profile loaded for: ${name} with pubkey: ${userPubkey}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout function
|
// Logout function
|
||||||
@@ -1275,12 +1406,11 @@
|
|||||||
isLoggedIn = false;
|
isLoggedIn = false;
|
||||||
currentConfig = null;
|
currentConfig = null;
|
||||||
|
|
||||||
// Reset UI
|
// Reset UI - keep persistent auth container visible
|
||||||
mainInterface.classList.add('hidden');
|
// mainInterface.classList.add('hidden');
|
||||||
loginSection.classList.remove('hidden');
|
loginSection.classList.remove('hidden');
|
||||||
updateConfigStatus(false);
|
updateConfigStatus(false);
|
||||||
relayStatus.textContent = 'READY TO FETCH';
|
updateLoginLogoutButton();
|
||||||
relayStatus.className = 'status disconnected';
|
|
||||||
|
|
||||||
console.log('Logged out successfully');
|
console.log('Logged out successfully');
|
||||||
|
|
||||||
@@ -1291,12 +1421,8 @@
|
|||||||
|
|
||||||
function updateConfigStatus(loaded) {
|
function updateConfigStatus(loaded) {
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
configStatus.textContent = 'CONFIGURATION LOADED';
|
|
||||||
configStatus.className = 'status connected';
|
|
||||||
configDisplay.classList.remove('hidden');
|
configDisplay.classList.remove('hidden');
|
||||||
} else {
|
} else {
|
||||||
configStatus.textContent = 'NO CONFIGURATION LOADED';
|
|
||||||
configStatus.className = 'status disconnected';
|
|
||||||
configDisplay.classList.add('hidden');
|
configDisplay.classList.add('hidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1324,8 +1450,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Connecting to relay via SimplePool: ${url}`);
|
console.log(`Connecting to relay via SimplePool: ${url}`);
|
||||||
relayStatus.textContent = 'CONNECTING...';
|
|
||||||
relayStatus.className = 'status connected';
|
|
||||||
|
|
||||||
// Clean up existing pool
|
// Clean up existing pool
|
||||||
if (relayPool) {
|
if (relayPool) {
|
||||||
@@ -1341,9 +1465,6 @@
|
|||||||
|
|
||||||
console.log(`Generated subscription ID: ${subscriptionId}`);
|
console.log(`Generated subscription ID: ${subscriptionId}`);
|
||||||
|
|
||||||
relayStatus.textContent = 'CONNECTED - SUBSCRIBING...';
|
|
||||||
relayStatus.className = 'status connected';
|
|
||||||
|
|
||||||
// Subscribe to kind 23457 events (admin response events)
|
// Subscribe to kind 23457 events (admin response events)
|
||||||
const subscription = relayPool.subscribeMany([url], [{
|
const subscription = relayPool.subscribeMany([url], [{
|
||||||
since: Math.floor(Date.now() / 1000),
|
since: Math.floor(Date.now() / 1000),
|
||||||
@@ -1367,9 +1488,6 @@
|
|||||||
|
|
||||||
// Process admin response event
|
// Process admin response event
|
||||||
processAdminResponse(event);
|
processAdminResponse(event);
|
||||||
|
|
||||||
relayStatus.textContent = 'SUBSCRIBED - LIVE UPDATES';
|
|
||||||
relayStatus.className = 'status connected';
|
|
||||||
},
|
},
|
||||||
oneose() {
|
oneose() {
|
||||||
console.log('EOSE received - End of stored events');
|
console.log('EOSE received - End of stored events');
|
||||||
@@ -1377,19 +1495,10 @@
|
|||||||
|
|
||||||
if (!currentConfig) {
|
if (!currentConfig) {
|
||||||
console.log('No configuration events were received');
|
console.log('No configuration events were received');
|
||||||
configStatus.textContent = 'NO CONFIGURATION EVENTS FOUND';
|
|
||||||
configStatus.className = 'status error';
|
|
||||||
relayStatus.textContent = 'SUBSCRIBED - NO EVENTS FOUND';
|
|
||||||
relayStatus.className = 'status error';
|
|
||||||
} else {
|
|
||||||
relayStatus.textContent = 'SUBSCRIBED - LIVE UPDATES';
|
|
||||||
relayStatus.className = 'status connected';
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onclose(reason) {
|
onclose(reason) {
|
||||||
console.log('Subscription closed:', reason);
|
console.log('Subscription closed:', reason);
|
||||||
relayStatus.textContent = 'SUBSCRIPTION CLOSED';
|
|
||||||
relayStatus.className = 'status error';
|
|
||||||
updateConfigStatus(false);
|
updateConfigStatus(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1404,9 +1513,6 @@
|
|||||||
console.error('Configuration subscription failed:', error.message);
|
console.error('Configuration subscription failed:', error.message);
|
||||||
console.error('Configuration subscription failed:', error);
|
console.error('Configuration subscription failed:', error);
|
||||||
console.error('Error stack:', error.stack);
|
console.error('Error stack:', error.stack);
|
||||||
|
|
||||||
relayStatus.textContent = 'SUBSCRIPTION FAILED';
|
|
||||||
relayStatus.className = 'status error';
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1468,7 +1574,7 @@
|
|||||||
// Handle auth query responses - updated to match backend response types
|
// Handle auth query responses - updated to match backend response types
|
||||||
if (responseData.query_type &&
|
if (responseData.query_type &&
|
||||||
(responseData.query_type.includes('auth_rules') ||
|
(responseData.query_type.includes('auth_rules') ||
|
||||||
responseData.query_type.includes('auth'))) {
|
responseData.query_type.includes('auth'))) {
|
||||||
console.log('Routing to auth query handler');
|
console.log('Routing to auth query handler');
|
||||||
handleAuthQueryResponse(responseData);
|
handleAuthQueryResponse(responseData);
|
||||||
return;
|
return;
|
||||||
@@ -1484,7 +1590,7 @@
|
|||||||
// Handle config query responses - updated to match backend response types
|
// Handle config query responses - updated to match backend response types
|
||||||
if (responseData.query_type &&
|
if (responseData.query_type &&
|
||||||
(responseData.query_type.includes('config') ||
|
(responseData.query_type.includes('config') ||
|
||||||
responseData.query_type.startsWith('config_'))) {
|
responseData.query_type.startsWith('config_'))) {
|
||||||
console.log('Routing to config query handler');
|
console.log('Routing to config query handler');
|
||||||
handleConfigQueryResponse(responseData);
|
handleConfigQueryResponse(responseData);
|
||||||
return;
|
return;
|
||||||
@@ -1558,8 +1664,6 @@
|
|||||||
} else {
|
} else {
|
||||||
console.log('No configuration data received');
|
console.log('No configuration data received');
|
||||||
updateConfigStatus(false);
|
updateConfigStatus(false);
|
||||||
configStatus.textContent = 'NO CONFIGURATION DATA RECEIVED';
|
|
||||||
configStatus.className = 'status error';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also log to test interface for debugging
|
// Also log to test interface for debugging
|
||||||
@@ -1866,21 +1970,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('Config query command sent successfully - waiting for response...');
|
console.log('Config query command sent successfully - waiting for response...');
|
||||||
configStatus.textContent = 'CONFIGURATION QUERY SENT - WAITING FOR RESPONSE';
|
|
||||||
configStatus.className = 'status connected';
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log('Not logged in - only subscription established for testing');
|
console.log('Not logged in - only subscription established for testing');
|
||||||
configStatus.textContent = 'SUBSCRIPTION ESTABLISHED - LOGIN REQUIRED FOR CONFIG QUERY';
|
|
||||||
configStatus.className = 'status disconnected';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch configuration:', error);
|
console.error('Failed to fetch configuration:', error);
|
||||||
configStatus.textContent = 'CONFIGURATION FETCH FAILED';
|
|
||||||
configStatus.className = 'status error';
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2224,8 +2322,39 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Login/Logout button functionality
|
||||||
|
function updateLoginLogoutButton() {
|
||||||
|
const loginLogoutBtn = document.getElementById('login-logout-btn');
|
||||||
|
if (!loginLogoutBtn) return;
|
||||||
|
|
||||||
|
if (isLoggedIn) {
|
||||||
|
loginLogoutBtn.textContent = 'LOGOUT';
|
||||||
|
loginLogoutBtn.className = 'login-logout-btn logout-state';
|
||||||
|
loginLogoutBtn.onclick = logout;
|
||||||
|
// Show user details when logged in
|
||||||
|
if (persistentUserDetails) {
|
||||||
|
persistentUserDetails.style.display = 'block';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loginLogoutBtn.textContent = 'ADMIN NOSTR LOGIN';
|
||||||
|
loginLogoutBtn.className = 'login-logout-btn';
|
||||||
|
loginLogoutBtn.onclick = () => {
|
||||||
|
if (window.NOSTR_LOGIN_LITE && window.NOSTR_LOGIN_LITE.launch) {
|
||||||
|
window.NOSTR_LOGIN_LITE.launch('login');
|
||||||
|
} else {
|
||||||
|
console.log('NOSTR_LOGIN_LITE not available');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Hide user details when logged out
|
||||||
|
if (persistentUserDetails) {
|
||||||
|
persistentUserDetails.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Event handlers
|
// Event handlers
|
||||||
logoutBtn.addEventListener('click', logout);
|
// Initialize login/logout button
|
||||||
|
updateLoginLogoutButton();
|
||||||
fetchConfigBtn.addEventListener('click', function (e) {
|
fetchConfigBtn.addEventListener('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -2336,9 +2465,18 @@
|
|||||||
function hideAuthRulesSection() {
|
function hideAuthRulesSection() {
|
||||||
if (authRulesSection) {
|
if (authRulesSection) {
|
||||||
authRulesSection.style.display = 'none';
|
authRulesSection.style.display = 'none';
|
||||||
authRulesTableContainer.style.display = 'none';
|
|
||||||
authRuleFormContainer.style.display = 'none';
|
// Add null checks for all elements
|
||||||
authRulesStatusDisplay.style.display = 'none';
|
if (authRulesTableContainer) {
|
||||||
|
authRulesTableContainer.style.display = 'none';
|
||||||
|
}
|
||||||
|
if (authRuleFormContainer) {
|
||||||
|
authRuleFormContainer.style.display = 'none';
|
||||||
|
}
|
||||||
|
if (authRulesStatusDisplay) {
|
||||||
|
authRulesStatusDisplay.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
currentAuthRules = [];
|
currentAuthRules = [];
|
||||||
editingAuthRule = null;
|
editingAuthRule = null;
|
||||||
log('Auth rules section hidden', 'INFO');
|
log('Auth rules section hidden', 'INFO');
|
||||||
@@ -2767,34 +2905,34 @@
|
|||||||
|
|
||||||
// Update existing logout and showMainInterface functions to handle auth rules
|
// Update existing logout and showMainInterface functions to handle auth rules
|
||||||
const originalLogout = logout;
|
const originalLogout = logout;
|
||||||
logout = async function() {
|
logout = async function () {
|
||||||
hideAuthRulesSection();
|
hideAuthRulesSection();
|
||||||
await originalLogout();
|
await originalLogout();
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalShowMainInterface = showMainInterface;
|
const originalShowMainInterface = showMainInterface;
|
||||||
showMainInterface = function() {
|
showMainInterface = function () {
|
||||||
originalShowMainInterface();
|
originalShowMainInterface();
|
||||||
showAuthRulesSection();
|
showAuthRulesSection();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Auth rules event handlers
|
// Auth rules event handlers
|
||||||
if (viewAuthRulesBtn) {
|
if (viewAuthRulesBtn) {
|
||||||
viewAuthRulesBtn.addEventListener('click', function(e) {
|
viewAuthRulesBtn.addEventListener('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
showAuthRulesTable();
|
showAuthRulesTable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addAuthRuleBtn) {
|
if (addAuthRuleBtn) {
|
||||||
addAuthRuleBtn.addEventListener('click', function(e) {
|
addAuthRuleBtn.addEventListener('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
showAddAuthRuleForm();
|
showAddAuthRuleForm();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refreshAuthRulesBtn) {
|
if (refreshAuthRulesBtn) {
|
||||||
refreshAuthRulesBtn.addEventListener('click', function(e) {
|
refreshAuthRulesBtn.addEventListener('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
loadAuthRules();
|
loadAuthRules();
|
||||||
});
|
});
|
||||||
@@ -2805,7 +2943,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cancelAuthRuleBtn) {
|
if (cancelAuthRuleBtn) {
|
||||||
cancelAuthRuleBtn.addEventListener('click', function(e) {
|
cancelAuthRuleBtn.addEventListener('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
hideAuthRuleForm();
|
hideAuthRuleForm();
|
||||||
});
|
});
|
||||||
@@ -3715,6 +3853,10 @@
|
|||||||
// Initialize the app
|
// Initialize the app
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
console.log('C-Relay Admin API interface loaded');
|
console.log('C-Relay Admin API interface loaded');
|
||||||
|
|
||||||
|
// Initialize login/logout button state
|
||||||
|
updateLoginLogoutButton();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
initializeApp();
|
initializeApp();
|
||||||
// Enhance SimplePool for testing after initialization
|
// Enhance SimplePool for testing after initialization
|
||||||
|
|||||||
Reference in New Issue
Block a user