2
This commit is contained in:
@@ -285,7 +285,6 @@
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const STORAGE_KEYS = ['access_token', 'AccessToken', 'ACCESS_TOKEN'];
|
||||
const ENDPOINTS = {
|
||||
summary: '/api/v1/user-online-devices/summary',
|
||||
info: '/api/v1/user/info',
|
||||
@@ -293,19 +292,95 @@
|
||||
};
|
||||
const REFRESH_MS = 30000;
|
||||
|
||||
function readToken(storage) {
|
||||
if (!storage) return '';
|
||||
for (const key of STORAGE_KEYS) {
|
||||
const value = storage.getItem(key);
|
||||
if (value) return value.replace(/^"|"$/g, '');
|
||||
}
|
||||
return '';
|
||||
function collectStringCandidates(value, bucket) {
|
||||
if (!value || typeof value !== 'string') return;
|
||||
|
||||
const trimmed = value.trim().replace(/^"|"$/g, '');
|
||||
if (!trimmed) return;
|
||||
|
||||
bucket.add(trimmed);
|
||||
|
||||
if (trimmed.startsWith('Bearer ')) {
|
||||
bucket.add(trimmed.slice(7).trim());
|
||||
}
|
||||
|
||||
function getAuthHeader() {
|
||||
const token = readToken(window.localStorage) || readToken(window.sessionStorage);
|
||||
if (!token) return '';
|
||||
if (trimmed[0] === '{' || trimmed[0] === '[') {
|
||||
try {
|
||||
collectFromUnknown(JSON.parse(trimmed), bucket);
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collectFromUnknown(input, bucket) {
|
||||
if (!input) return;
|
||||
|
||||
if (typeof input === 'string') {
|
||||
collectStringCandidates(input, bucket);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(input)) {
|
||||
input.forEach(function (item) {
|
||||
collectFromUnknown(item, bucket);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof input === 'object') {
|
||||
Object.keys(input).forEach(function (key) {
|
||||
collectFromUnknown(input[key], bucket);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function collectTokensFromStorage(storage, bucket) {
|
||||
if (!storage) return;
|
||||
|
||||
for (let i = 0; i < storage.length; i += 1) {
|
||||
const key = storage.key(i);
|
||||
if (!key) continue;
|
||||
collectStringCandidates(storage.getItem(key), bucket);
|
||||
}
|
||||
}
|
||||
|
||||
function buildTokenCandidates() {
|
||||
const bucket = new Set();
|
||||
collectTokensFromStorage(window.localStorage, bucket);
|
||||
collectTokensFromStorage(window.sessionStorage, bucket);
|
||||
|
||||
return Array.from(bucket)
|
||||
.map(function (token) {
|
||||
return token.startsWith('Bearer ') ? token : 'Bearer ' + token;
|
||||
})
|
||||
.filter(function (token) {
|
||||
const raw = token.replace(/^Bearer\s+/i, '').trim();
|
||||
return raw.length >= 20 && !/\s/.test(raw);
|
||||
});
|
||||
}
|
||||
|
||||
async function pickAuthorization() {
|
||||
const candidates = buildTokenCandidates();
|
||||
|
||||
for (const authorization of candidates) {
|
||||
try {
|
||||
const response = await fetch(ENDPOINTS.info, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': authorization
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
return authorization;
|
||||
}
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function formatTime(timestamp) {
|
||||
@@ -418,9 +493,9 @@
|
||||
}
|
||||
|
||||
async function loadPageData() {
|
||||
const authorization = getAuthHeader();
|
||||
const authorization = await pickAuthorization();
|
||||
if (!authorization) {
|
||||
setError('No login token found in browser storage. Please log in to Xboard first, then open /user-online-devices/userstatus.');
|
||||
setError('No usable login token was found in browser storage. Please open the Xboard homepage first, complete login there, then refresh this page.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user