Профиль: реальные UserParam данные в правой вкладке и обновление через сервер

This commit is contained in:
ai5590
2026-04-05 20:39:17 +03:00
parent cf5460c5c7
commit 525627c972
8 changed files with 385 additions and 56 deletions
+47 -1
View File
@@ -8,9 +8,10 @@ import {
randomBase64,
signBase64,
} from './crypto-utils.js?v=20260403081123';
import { loadSessionMaterial, saveEncryptedUserSecrets, saveSessionMaterial } from './key-vault.js?v=20260403081123';
import { loadEncryptedUserSecrets, loadSessionMaterial, saveEncryptedUserSecrets, saveSessionMaterial } from './key-vault.js?v=20260403081123';
const BCH_SUFFIX = '001';
const USER_PARAMETER_PREFIX = 'SHiNe/UserParameter:';
function normalizeServerUrl(url) {
const value = (url || '').trim();
@@ -235,6 +236,51 @@ export class AuthService {
return response.payload || {};
}
async listUserParams(login) {
const cleanLogin = (login || '').trim();
if (!cleanLogin) throw new Error('Не передан login');
const response = await this.ws.request('ListUserParams', { login: cleanLogin });
if (response.status !== 200) throw opError('ListUserParams', response);
return response.payload || {};
}
async upsertUserParam({ login, param, value, timeMs = Date.now(), storagePwd }) {
const cleanLogin = (login || '').trim();
const cleanParam = (param || '').trim();
if (!cleanLogin || !cleanParam) throw new Error('Не переданы login/param');
if (!storagePwd) throw new Error('Не передан storagePwd для подписи UserParam');
const user = await this.getUser(cleanLogin);
const deviceKey = String(user?.deviceKey || '').trim();
if (!deviceKey) {
throw new Error('GetUser не вернул deviceKey для подписи UserParam');
}
const savedKeys = await loadEncryptedUserSecrets(cleanLogin, storagePwd);
const devicePrivatePkcs8 = savedKeys?.deviceKey;
if (!devicePrivatePkcs8) {
throw new Error('На устройстве нет сохраненного приватного deviceKey');
}
const privateKey = await importPkcs8Ed25519(devicePrivatePkcs8);
const cleanValue = String(value ?? '');
const signText = `${USER_PARAMETER_PREFIX}${cleanLogin}${cleanParam}${timeMs}${cleanValue}`;
const signature = await signBase64(privateKey, signText);
const response = await this.ws.request('UpsertUserParam', {
login: cleanLogin,
param: cleanParam,
time_ms: Number(timeMs),
value: cleanValue,
device_key: deviceKey,
signature,
});
if (response.status !== 200) throw opError('UpsertUserParam', response);
return response.payload || {};
}
async reportClientError(details) {
try {
const response = await this.ws.request('ClientErrorLog', details || {}, 3000);
@@ -0,0 +1,68 @@
import { authService, state } from '../state.js?v=20260403081123';
export const profileFieldDefs = [
{ key: 'first_name', readKeys: ['first_name', 'name'], label: 'First name', placeholder: 'Введите имя' },
{ key: 'last_name', readKeys: ['last_name'], label: 'Last name', placeholder: 'Введите фамилию' },
{ key: 'address_physical', readKeys: ['address_physical'], label: 'Address physical', placeholder: 'Город, улица, дом' },
{ key: 'address_web', readKeys: ['address_web'], label: 'Address web', placeholder: 'Сайт или профиль' },
{ key: 'phone', readKeys: ['phone'], label: 'Phone', placeholder: '+7 ...' },
];
function normalizeItems(responsePayload) {
const params = responsePayload?.params;
if (!Array.isArray(params)) return [];
return params
.map((item) => ({
param: String(item?.param || '').trim(),
value: String(item?.value || ''),
timeMs: Number(item?.time_ms || 0),
}))
.filter((item) => item.param);
}
function getLatestByAliases(items, aliases) {
let latest = null;
items.forEach((item) => {
if (!aliases.includes(item.param)) return;
if (!latest || item.timeMs >= latest.timeMs) {
latest = item;
}
});
return latest;
}
export async function loadProfileParams(login) {
const payload = await authService.listUserParams(login);
const items = normalizeItems(payload);
return profileFieldDefs.map((field) => {
const latest = getLatestByAliases(items, field.readKeys);
return {
key: field.key,
label: field.label,
placeholder: field.placeholder,
value: latest?.value || '',
timeMs: latest?.timeMs || 0,
};
});
}
export async function saveProfileParams(login, valuesByKey) {
const storagePwd = state.session.storagePwdInMemory;
if (!storagePwd) {
throw new Error('Нет storagePwd в памяти сессии. Выполните вход заново.');
}
const baseTime = Date.now();
for (let i = 0; i < profileFieldDefs.length; i += 1) {
const field = profileFieldDefs[i];
await authService.upsertUserParam({
login,
param: field.key,
value: String(valuesByKey[field.key] || '').trim(),
timeMs: baseTime + i,
storagePwd,
});
}
}