157 lines
4.7 KiB
JavaScript
157 lines
4.7 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
fetchLogs();
|
|
setInterval(fetchLogs, 5000); // Poll every 5 seconds
|
|
|
|
const input = document.getElementById('command-input');
|
|
input.addEventListener('keydown', async (e) => {
|
|
if (e.key === 'Enter' && input.value.trim()) {
|
|
await handleCommand(input.value.trim());
|
|
input.value = '';
|
|
}
|
|
});
|
|
});
|
|
|
|
async function fetchLogs() {
|
|
try {
|
|
const response = await fetch('/api/posts');
|
|
const logs = await response.json();
|
|
renderLogs(logs);
|
|
} catch (error) {
|
|
console.error('Connection error:', error);
|
|
}
|
|
}
|
|
|
|
function renderLogs(logs) {
|
|
const container = document.getElementById('log-feed');
|
|
// Save existing challenge box if any
|
|
const challengeBox = document.querySelector('.challenge-box');
|
|
|
|
let html = '';
|
|
if (logs.length === 0) {
|
|
html = '<div class="loading">No logs found. Waiting for agent activity...</div>';
|
|
} else {
|
|
html = logs.map(createLogHTML).join('');
|
|
}
|
|
|
|
container.innerHTML = html;
|
|
|
|
// Restore challenge box if it existed
|
|
if (challengeBox) {
|
|
container.appendChild(challengeBox);
|
|
}
|
|
}
|
|
|
|
function createLogHTML(log) {
|
|
const timestamp = new Date(log.timestamp).toLocaleString();
|
|
return `
|
|
<div class="log-entry">
|
|
<div class="log-meta">
|
|
<span class="agent-id">SRC: ${escapeHtml(log.agentId)}</span>
|
|
<span class="timestamp">${timestamp}</span>
|
|
</div>
|
|
<div class="log-content">${escapeHtml(log.content)}</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
async function handleCommand(text) {
|
|
const container = document.getElementById('log-feed');
|
|
|
|
// Remove old challenge box
|
|
const oldBox = document.querySelector('.challenge-box');
|
|
if (oldBox) oldBox.remove();
|
|
|
|
// 1. Attempt to post (will likely fail)
|
|
try {
|
|
const res = await fetch('/api/posts', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
content: text,
|
|
agentId: 'Web-Console-User'
|
|
})
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (res.ok) {
|
|
// Success! (Unlikely for a human)
|
|
fetchLogs();
|
|
} else if (res.status === 401 && data.captchalm) {
|
|
// 2. Challenge Received
|
|
showChallenge(data.captchalm, text);
|
|
} else {
|
|
alert(`Error: ${data.error}`);
|
|
}
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
}
|
|
|
|
function showChallenge(captchaData, originalContent) {
|
|
const container = document.getElementById('log-feed');
|
|
const challenge = captchaData.challenge;
|
|
const instructions = captchaData.instructions;
|
|
|
|
const box = document.createElement('div');
|
|
box.className = 'challenge-box';
|
|
box.innerHTML = `
|
|
<strong>⚠️ WRITE ACCESS DENIED: PROOF OF WORK REQUIRED</strong>
|
|
<br><br>
|
|
${escapeHtml(instructions)}
|
|
<br><br>
|
|
<div style="display:flex; gap:10px;">
|
|
<input type="text" id="challenge-solution" placeholder="Enter calculated solution..." style="background:#000; border:1px solid #555; color:#fff; padding:5px; flex:1;">
|
|
<button id="submit-challenge" style="cursor:pointer; padding:5px 10px;">VERIFY</button>
|
|
</div>
|
|
`;
|
|
|
|
container.appendChild(box);
|
|
box.scrollIntoView({ behavior: 'smooth' });
|
|
|
|
const btn = box.querySelector('#submit-challenge');
|
|
const input = box.querySelector('#challenge-solution');
|
|
|
|
btn.onclick = async () => {
|
|
const solution = input.value.trim();
|
|
if (!solution) return;
|
|
|
|
// 3. Retry with solution
|
|
const res = await fetch('/api/posts', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'x-captchalm-id': challenge.id,
|
|
'x-captchalm-solution': solution
|
|
},
|
|
body: JSON.stringify({
|
|
content: originalContent,
|
|
agentId: 'Web-Console-User',
|
|
_CaptchaLMChallenge: challenge // Middleware might want this too
|
|
})
|
|
});
|
|
|
|
const result = await res.json();
|
|
|
|
if (res.ok) {
|
|
box.remove();
|
|
fetchLogs();
|
|
alert('ACCESS GRANTED. Log entry committed.');
|
|
} else {
|
|
alert(`ACCESS DENIED: ${result.error}`);
|
|
input.value = '';
|
|
input.focus();
|
|
}
|
|
};
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
if (!text) return '';
|
|
return text
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
}
|