205 lines
6.4 KiB
HTML
205 lines
6.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SigSocket Client Demo</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
h1, h2 {
|
|
color: #333;
|
|
text-align: center;
|
|
}
|
|
|
|
.status-box {
|
|
text-align: center;
|
|
padding: 15px;
|
|
margin-bottom: 30px;
|
|
border-radius: 5px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.status-connected {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
border: 1px solid #c3e6cb;
|
|
}
|
|
|
|
.client-info {
|
|
margin-bottom: 30px;
|
|
padding: 15px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 5px;
|
|
background-color: #f9f9f9;
|
|
}
|
|
|
|
.keypair-info {
|
|
font-family: monospace;
|
|
word-break: break-all;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.request-panel {
|
|
padding: 20px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 5px;
|
|
margin-bottom: 30px;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.message-box {
|
|
font-family: monospace;
|
|
background-color: #f8f9fa;
|
|
padding: 15px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
margin: 15px 0;
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.no-requests {
|
|
text-align: center;
|
|
padding: 30px;
|
|
color: #6c757d;
|
|
}
|
|
|
|
button {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
padding: 10px 15px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
display: block;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
button:hover {
|
|
background-color: #45a049;
|
|
}
|
|
|
|
.footer {
|
|
text-align: center;
|
|
margin-top: 30px;
|
|
color: #6c757d;
|
|
font-size: 0.9em;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>SigSocket Client Demo</h1>
|
|
|
|
<div class="status-box status-connected">
|
|
<p><strong>Status:</strong> Connected to SigSocket Server</p>
|
|
</div>
|
|
|
|
<div class="client-info">
|
|
<h2>Client Information</h2>
|
|
<p><strong>Public Key:</strong></p>
|
|
<p class="keypair-info">{{ public_key }}</p>
|
|
<p>This public key is used to identify this client to the SigSocket server.</p>
|
|
</div>
|
|
|
|
{% if request %}
|
|
<div class="request-panel">
|
|
<h2>Pending Sign Request</h2>
|
|
<p><strong>Request ID:</strong> {{ request.id }}</p>
|
|
|
|
<p><strong>Message to Sign:</strong></p>
|
|
<div class="message-box">{{ request.message }}</div>
|
|
|
|
<form action="/sign" method="post">
|
|
<input type="hidden" name="id" value="{{ request.id }}">
|
|
<button type="submit">Sign Message</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<div class="request-panel no-requests">
|
|
<h2>No Pending Requests</h2>
|
|
<p>Waiting for a sign request from the SigSocket server...</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="footer">
|
|
<p>This client connects to a SigSocket server via WebSocket and responds to signature requests.</p>
|
|
<p>The signing is done using Secp256k1 ECDSA with a randomly generated keypair.</p>
|
|
</div>
|
|
|
|
<!-- Toast container for notifications -->
|
|
<div class="toast-container position-fixed bottom-0 start-0 p-3" style="z-index: 11; width: 100%;">
|
|
<!-- Toasts will be added here dynamically -->
|
|
</div>
|
|
|
|
<script>
|
|
// Override console.log to show toast messages
|
|
const originalConsoleLog = console.log;
|
|
const originalConsoleError = console.error;
|
|
|
|
console.log = function(message) {
|
|
// Call the original console.log
|
|
originalConsoleLog.apply(console, arguments);
|
|
// Show toast with the message
|
|
showToast(message, 'info');
|
|
};
|
|
|
|
console.error = function(message) {
|
|
// Call the original console.error
|
|
originalConsoleError.apply(console, arguments);
|
|
// Show toast with the error message
|
|
showToast(message, 'danger');
|
|
};
|
|
|
|
function showToast(message, type = 'info') {
|
|
// Create toast element
|
|
const toastId = 'toast-' + Date.now();
|
|
const toastElement = document.createElement('div');
|
|
toastElement.id = toastId;
|
|
toastElement.className = 'toast w-100';
|
|
toastElement.setAttribute('role', 'alert');
|
|
toastElement.setAttribute('aria-live', 'assertive');
|
|
toastElement.setAttribute('aria-atomic', 'true');
|
|
|
|
// Set toast content
|
|
toastElement.innerHTML = `
|
|
<div class="toast-header bg-${type} text-white">
|
|
<strong class="me-auto">${type === 'danger' ? 'Error' : 'Info'}</strong>
|
|
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
</div>
|
|
<div class="toast-body">
|
|
${message}
|
|
</div>
|
|
`;
|
|
|
|
// Append to container
|
|
document.querySelector('.toast-container').appendChild(toastElement);
|
|
|
|
// Initialize and show the toast
|
|
const toast = new bootstrap.Toast(toastElement, {
|
|
autohide: true,
|
|
delay: 5000
|
|
});
|
|
toast.show();
|
|
|
|
// Remove toast after it's hidden
|
|
toastElement.addEventListener('hidden.bs.toast', () => {
|
|
toastElement.remove();
|
|
});
|
|
}
|
|
|
|
// Test toast
|
|
console.log('Client app loaded successfully!');
|
|
</script>
|
|
</body>
|
|
</html>
|