SHA256
Ограничил access servers до двух в UI и сервере
This commit is contained in:
@@ -7,6 +7,7 @@ import { readShineUserPda, updateShineUserPdaOnSolana } from '../services/shine-
|
||||
import { getTopupSiteUrl } from '../services/solana-wallet-service.js';
|
||||
|
||||
export const pageMeta = { id: 'access-servers-view', title: 'Серверы доступа' };
|
||||
const MAX_ACCESS_SERVERS = 2;
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value || '')
|
||||
@@ -39,8 +40,9 @@ function uniqueLogins(values) {
|
||||
if (!login || seen.has(login)) return;
|
||||
seen.add(login);
|
||||
result.push(login);
|
||||
if (result.length >= MAX_ACCESS_SERVERS) return;
|
||||
});
|
||||
return result;
|
||||
return result.slice(0, MAX_ACCESS_SERVERS);
|
||||
}
|
||||
|
||||
function shortenSignature(value) {
|
||||
@@ -309,7 +311,7 @@ export function render({ navigate }) {
|
||||
addTitle.textContent = 'Добавить сервер доступа';
|
||||
const addHint = document.createElement('p');
|
||||
addHint.className = 'meta-muted';
|
||||
addHint.textContent = 'Введите логин сервера или несколько первых букв, затем выберите сервер из подсказок.';
|
||||
addHint.textContent = 'Можно использовать максимум два сервера доступа. Введите логин сервера или несколько первых букв, затем выберите сервер из подсказок.';
|
||||
const addInput = document.createElement('input');
|
||||
addInput.className = 'input';
|
||||
addInput.type = 'text';
|
||||
@@ -329,7 +331,9 @@ export function render({ navigate }) {
|
||||
addCard.append(addTitle, addHint, addInput, suggestEl, addStatus, addButton);
|
||||
|
||||
const refreshAddButton = () => {
|
||||
addButton.disabled = operationBusy || (!selectedCandidate && !normalizeLogin(addInput.value));
|
||||
addButton.disabled = operationBusy
|
||||
|| currentAccessServers.length >= MAX_ACCESS_SERVERS
|
||||
|| (!selectedCandidate && !normalizeLogin(addInput.value));
|
||||
};
|
||||
|
||||
const setOperationBusy = (busy) => {
|
||||
@@ -348,7 +352,9 @@ export function render({ navigate }) {
|
||||
addInput.value = candidate.login;
|
||||
addStatus.textContent = `Выбран сервер @${candidate.login}${candidate.url ? ` (${candidate.url})` : ''}`;
|
||||
} else {
|
||||
addStatus.textContent = 'Для изменения списка понадобится подпись root key.';
|
||||
addStatus.textContent = currentAccessServers.length >= MAX_ACCESS_SERVERS
|
||||
? 'У пользователя уже выбраны два сервера доступа. Сначала отключите один из них.'
|
||||
: 'Для изменения списка понадобится подпись root key.';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -457,12 +463,17 @@ export function render({ navigate }) {
|
||||
}
|
||||
currentAccessServers = rows;
|
||||
renderServerList();
|
||||
refreshAddButton();
|
||||
listStatus.textContent = rows.length
|
||||
? `Найдено серверов доступа: ${rows.length}`
|
||||
: 'В PDA пользователя пока нет серверов доступа.';
|
||||
if (rows.length >= MAX_ACCESS_SERVERS) {
|
||||
addStatus.textContent = 'У пользователя уже выбраны два сервера доступа. Сначала отключите один из них.';
|
||||
}
|
||||
} catch (error) {
|
||||
currentAccessServers = [];
|
||||
renderServerList();
|
||||
refreshAddButton();
|
||||
listStatus.textContent = error?.message || 'Не удалось прочитать список серверов доступа.';
|
||||
}
|
||||
};
|
||||
@@ -654,6 +665,10 @@ export function render({ navigate }) {
|
||||
addStatus.textContent = `Сервер @${login} уже есть в списке.`;
|
||||
return;
|
||||
}
|
||||
if (currentAccessServers.length >= MAX_ACCESS_SERVERS) {
|
||||
addStatus.textContent = 'Нельзя добавить больше двух серверов доступа. Сначала отключите один из текущих.';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const resolved = await resolveShineServerByServerLogin({ serverLogin: login, solanaEndpoint });
|
||||
|
||||
@@ -69,7 +69,7 @@ export async function resolveShineServerForUserLogin({ login, solanaEndpoint, fa
|
||||
solanaEndpoint,
|
||||
});
|
||||
const accessServers = Array.isArray(parsedUser?.accessServers)
|
||||
? parsedUser.accessServers.map((value) => normalizeShineServerLogin(value)).filter(Boolean)
|
||||
? parsedUser.accessServers.map((value) => normalizeShineServerLogin(value)).filter(Boolean).slice(0, 2)
|
||||
: [];
|
||||
const pickedServerLogin = accessServers[0] || normalizeShineServerLogin(fallbackServerLogin);
|
||||
if (!pickedServerLogin) {
|
||||
|
||||
@@ -30,6 +30,7 @@ const BLOCK_TYPE_TRUSTED_STATE = 70;
|
||||
const SESSIONS_MODE_MIXED = 1;
|
||||
const SESSION_TYPE_USER = 1;
|
||||
const SESSION_TYPE_HOMESERVER = 100;
|
||||
const MAX_EFFECTIVE_ACCESS_SERVERS = 2;
|
||||
|
||||
let solanaLibPromise = null;
|
||||
function loadSolanaLib() {
|
||||
@@ -41,6 +42,19 @@ function normalizeLogin(login) {
|
||||
return String(login || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function normalizeAccessServers(values) {
|
||||
const seen = new Set();
|
||||
const result = [];
|
||||
for (const value of Array.isArray(values) ? values : []) {
|
||||
const login = normalizeLogin(value);
|
||||
if (!login || seen.has(login)) continue;
|
||||
seen.add(login);
|
||||
result.push(login);
|
||||
if (result.length >= MAX_EFFECTIVE_ACCESS_SERVERS) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function pushU32LE(buf, value) {
|
||||
const n = Number(value) >>> 0;
|
||||
buf.push(n & 0xff, (n >>> 8) & 0xff, (n >>> 16) & 0xff, (n >>> 24) & 0xff);
|
||||
@@ -202,7 +216,7 @@ function serializeCreateUserPdaArgs(args) {
|
||||
buf.push(syncServers.length & 0xff);
|
||||
for (const value of syncServers) pushStrU8(buf, value);
|
||||
}
|
||||
const accessServers = Array.isArray(args.accessServers) ? args.accessServers : [];
|
||||
const accessServers = normalizeAccessServers(args.accessServers);
|
||||
buf.push(accessServers.length & 0xff);
|
||||
for (const value of accessServers) pushStrU8(buf, value);
|
||||
buf.push(Number(args.sessionsMode || SESSIONS_MODE_MIXED) & 0xff);
|
||||
@@ -252,7 +266,7 @@ function serializeUpdateUserPdaArgs(args) {
|
||||
buf.push(syncServers.length & 0xff);
|
||||
for (const value of syncServers) pushStrU8(buf, value);
|
||||
}
|
||||
const accessServers = Array.isArray(args.accessServers) ? args.accessServers : [];
|
||||
const accessServers = normalizeAccessServers(args.accessServers);
|
||||
buf.push(accessServers.length & 0xff);
|
||||
for (const value of accessServers) pushStrU8(buf, value);
|
||||
buf.push(Number(args.sessionsMode || SESSIONS_MODE_MIXED) & 0xff);
|
||||
@@ -337,7 +351,7 @@ function createPdaState({
|
||||
addressFormatVersion: serverProfile?.addressFormatVersion ?? 0,
|
||||
serverAddress: serverProfile?.serverAddress ?? '',
|
||||
syncServers: serverProfile?.syncServers ? [...serverProfile.syncServers] : [],
|
||||
accessServers: Array.isArray(accessServers) ? [...accessServers] : [],
|
||||
accessServers: normalizeAccessServers(accessServers),
|
||||
sessionsMode: Number(sessionsMode || SESSIONS_MODE_MIXED) & 0xff,
|
||||
sessions: Array.isArray(sessions) ? sessions.map((x) => ({
|
||||
sessionType: Number(x?.sessionType || 0) & 0xff,
|
||||
@@ -493,6 +507,7 @@ export function parseShineUserPda(dataBytes) {
|
||||
const accessCount = reader.readU8();
|
||||
accessServers = [];
|
||||
for (let j = 0; j < accessCount; j += 1) accessServers.push(reader.readStrU8());
|
||||
accessServers = normalizeAccessServers(accessServers);
|
||||
continue;
|
||||
}
|
||||
if (blockType === BLOCK_TYPE_SESSIONS) {
|
||||
|
||||
Reference in New Issue
Block a user