229 lines
6.9 KiB
JavaScript
229 lines
6.9 KiB
JavaScript
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);
|