+228
@@ -0,0 +1,228 @@
|
||||
const els = {
|
||||
adminStatus: document.querySelector('#adminStatus'),
|
||||
credentialsSource: document.querySelector('#credentialsSource'),
|
||||
tokenStatus: document.querySelector('#tokenStatus'),
|
||||
steamStatus: document.querySelector('#steamStatus'),
|
||||
gcStatus: document.querySelector('#gcStatus'),
|
||||
loginPanel: document.querySelector('#loginPanel'),
|
||||
credentialsPanel: document.querySelector('#credentialsPanel'),
|
||||
guardPanel: document.querySelector('#guardPanel'),
|
||||
tokenPanel: document.querySelector('#tokenPanel'),
|
||||
adminPassword: document.querySelector('#adminPassword'),
|
||||
unlockBtn: document.querySelector('#unlockBtn'),
|
||||
adminError: document.querySelector('#adminError'),
|
||||
adminMessage: document.querySelector('#adminMessage'),
|
||||
steamAccount: document.querySelector('#steamAccount'),
|
||||
steamPassword: document.querySelector('#steamPassword'),
|
||||
clearToken: document.querySelector('#clearToken'),
|
||||
reloadBtn: document.querySelector('#reloadBtn'),
|
||||
saveBtn: document.querySelector('#saveBtn'),
|
||||
steamGuardCode: document.querySelector('#steamGuardCode'),
|
||||
submitGuardBtn: document.querySelector('#submitGuardBtn'),
|
||||
guardHint: document.querySelector('#guardHint'),
|
||||
tokenSteamId: document.querySelector('#tokenSteamId'),
|
||||
tokenAccount: document.querySelector('#tokenAccount'),
|
||||
tokenUpdated: document.querySelector('#tokenUpdated'),
|
||||
tokenExpires: document.querySelector('#tokenExpires'),
|
||||
clearTokenBtn: document.querySelector('#clearTokenBtn'),
|
||||
};
|
||||
|
||||
let adminPassword = sessionStorage.getItem('dokaAdminPassword') || '';
|
||||
let credentialsDirty = false;
|
||||
|
||||
const dateTimeFormat = new Intl.DateTimeFormat('en-GB', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
});
|
||||
|
||||
function formatDate(iso) {
|
||||
if (!iso) return '-';
|
||||
const date = new Date(iso);
|
||||
if (Number.isNaN(date.getTime())) return '-';
|
||||
return dateTimeFormat.format(date);
|
||||
}
|
||||
|
||||
function setBadge(label, klass) {
|
||||
els.adminStatus.textContent = label;
|
||||
els.adminStatus.className = `badge ${klass}`;
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
els.adminError.hidden = !message;
|
||||
els.adminError.textContent = message || '';
|
||||
}
|
||||
|
||||
function showMessage(message) {
|
||||
els.adminMessage.hidden = !message;
|
||||
els.adminMessage.textContent = message || '';
|
||||
}
|
||||
|
||||
async function adminFetch(url, options = {}) {
|
||||
const res = await fetch(url, {
|
||||
...options,
|
||||
cache: 'no-store',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Admin-Password': adminPassword,
|
||||
...(options.headers || {}),
|
||||
},
|
||||
});
|
||||
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
function unlocked() {
|
||||
return Boolean(adminPassword);
|
||||
}
|
||||
|
||||
function render(data, options = {}) {
|
||||
const preserveEditedInputs = options.preserveEditedInputs !== false;
|
||||
const connection = data.connection || {};
|
||||
const credentials = data.credentials || {};
|
||||
const token = data.refreshToken || {};
|
||||
const steamGuard = connection.steamGuard || {};
|
||||
|
||||
els.loginPanel.hidden = unlocked();
|
||||
els.credentialsPanel.hidden = !unlocked();
|
||||
els.tokenPanel.hidden = !unlocked();
|
||||
els.guardPanel.hidden = !unlocked() || !steamGuard.required;
|
||||
|
||||
setBadge(unlocked() ? 'unlocked' : 'locked', unlocked() ? 'badge-ok' : 'badge-muted');
|
||||
els.credentialsSource.textContent = credentials.source || '-';
|
||||
els.tokenStatus.textContent = token.exists ? 'saved' : 'missing';
|
||||
els.steamStatus.textContent = connection.steam || '-';
|
||||
els.gcStatus.textContent = connection.gc || '-';
|
||||
|
||||
const editingCredentials = document.activeElement === els.steamAccount
|
||||
|| document.activeElement === els.steamPassword
|
||||
|| credentialsDirty;
|
||||
|
||||
if (!preserveEditedInputs || !editingCredentials) {
|
||||
els.steamAccount.value = credentials.accountName || '';
|
||||
els.steamPassword.value = credentials.password || '';
|
||||
credentialsDirty = false;
|
||||
}
|
||||
|
||||
els.tokenSteamId.textContent = token.steamID || '-';
|
||||
els.tokenAccount.textContent = token.accountName || '-';
|
||||
els.tokenUpdated.textContent = formatDate(token.updatedAt);
|
||||
els.tokenExpires.textContent = formatDate(token.expiresAt);
|
||||
|
||||
if (steamGuard.required) {
|
||||
const where = steamGuard.domain ? `Email domain: ${steamGuard.domain}` : 'Mobile authenticator code required';
|
||||
els.guardHint.textContent = steamGuard.lastCodeWrong ? `Last code was rejected. ${where}.` : where;
|
||||
} else {
|
||||
els.guardHint.textContent = '';
|
||||
}
|
||||
}
|
||||
|
||||
async function loadAuth(options = {}) {
|
||||
if (!unlocked()) {
|
||||
render({});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
showError('');
|
||||
const data = await adminFetch('/api/admin/auth');
|
||||
render(data, options);
|
||||
} catch (err) {
|
||||
showError(err.message);
|
||||
if (err.message.includes('Invalid admin password')) {
|
||||
adminPassword = '';
|
||||
sessionStorage.removeItem('dokaAdminPassword');
|
||||
}
|
||||
render({});
|
||||
}
|
||||
}
|
||||
|
||||
async function saveCredentials() {
|
||||
try {
|
||||
showError('');
|
||||
showMessage('');
|
||||
const data = await adminFetch('/api/admin/auth', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({
|
||||
accountName: els.steamAccount.value,
|
||||
password: els.steamPassword.value,
|
||||
clearRefreshToken: els.clearToken.checked,
|
||||
}),
|
||||
});
|
||||
credentialsDirty = false;
|
||||
render(data);
|
||||
showMessage('Credentials saved. Reconnect started.');
|
||||
} catch (err) {
|
||||
showError(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitSteamGuard() {
|
||||
try {
|
||||
showError('');
|
||||
showMessage('');
|
||||
const data = await adminFetch('/api/admin/steam-guard', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ code: els.steamGuardCode.value }),
|
||||
});
|
||||
els.steamGuardCode.value = '';
|
||||
render(data);
|
||||
showMessage('Steam Guard code submitted.');
|
||||
} catch (err) {
|
||||
showError(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function clearRefreshToken() {
|
||||
try {
|
||||
showError('');
|
||||
showMessage('');
|
||||
const data = await adminFetch('/api/admin/clear-token', { method: 'POST', body: '{}' });
|
||||
render(data);
|
||||
showMessage('Refresh token cleared.');
|
||||
} catch (err) {
|
||||
showError(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
els.unlockBtn.addEventListener('click', () => {
|
||||
adminPassword = els.adminPassword.value;
|
||||
sessionStorage.setItem('dokaAdminPassword', adminPassword);
|
||||
loadAuth({ preserveEditedInputs: false });
|
||||
});
|
||||
|
||||
els.adminPassword.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter') els.unlockBtn.click();
|
||||
});
|
||||
|
||||
els.reloadBtn.addEventListener('click', () => {
|
||||
credentialsDirty = false;
|
||||
loadAuth({ preserveEditedInputs: false });
|
||||
});
|
||||
els.saveBtn.addEventListener('click', saveCredentials);
|
||||
els.submitGuardBtn.addEventListener('click', submitSteamGuard);
|
||||
els.clearTokenBtn.addEventListener('click', clearRefreshToken);
|
||||
|
||||
els.steamAccount.addEventListener('input', () => {
|
||||
credentialsDirty = true;
|
||||
});
|
||||
|
||||
els.steamPassword.addEventListener('input', () => {
|
||||
credentialsDirty = true;
|
||||
});
|
||||
|
||||
els.steamGuardCode.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter') els.submitGuardBtn.click();
|
||||
});
|
||||
|
||||
if (adminPassword) {
|
||||
els.adminPassword.value = adminPassword;
|
||||
}
|
||||
|
||||
loadAuth({ preserveEditedInputs: false });
|
||||
setInterval(loadAuth, 5000);
|
||||
Reference in New Issue
Block a user