diff --git a/SHiNE-server/src/test/java/test/it/IT_DeployBackupCleanAndRunRemoteMain.java b/SHiNE-server/src/test/java/test/it/IT_DeployBackupCleanAndRunRemoteMain.java index 88350f7..5db7df1 100644 --- a/SHiNE-server/src/test/java/test/it/IT_DeployBackupCleanAndRunRemoteMain.java +++ b/SHiNE-server/src/test/java/test/it/IT_DeployBackupCleanAndRunRemoteMain.java @@ -19,10 +19,10 @@ import java.util.jar.JarFile; */ public class IT_DeployBackupCleanAndRunRemoteMain { - private static final String REMOTE_HOST = System.getProperty("it.remoteHost", "194.87.0.247"); - private static final String REMOTE_USER = System.getProperty("it.remoteUser", "user"); + private static final String REMOTE_HOST = System.getProperty("it.remoteHost", "shineup.me"); + private static final String REMOTE_USER = System.getProperty("it.remoteUser", "player"); - private static final String REMOTE_DIR = System.getProperty("it.remoteDir", "/home/user/docker/shine-server"); + private static final String REMOTE_DIR = System.getProperty("it.remoteDir", "/home/player/SHiNE/shine-server"); private static final String REMOTE_JAR = REMOTE_DIR + "/shine-server.jar"; private static final String REMOTE_DATA = System.getProperty("it.remoteDataDir", REMOTE_DIR + "/data"); private static final String REMOTE_BACKUP_DIR = System.getProperty("it.remoteBackupDir", REMOTE_DIR + "/backup"); diff --git a/SHiNE-server/src/test/java/test/it/IT_DeployRestartAndRunRemoteMain.java b/SHiNE-server/src/test/java/test/it/IT_DeployRestartAndRunRemoteMain.java index 2ed0afe..253367a 100644 --- a/SHiNE-server/src/test/java/test/it/IT_DeployRestartAndRunRemoteMain.java +++ b/SHiNE-server/src/test/java/test/it/IT_DeployRestartAndRunRemoteMain.java @@ -11,10 +11,10 @@ import java.util.Objects; public class IT_DeployRestartAndRunRemoteMain { // ====== НАСТРОЙКИ (можно переопределять systemProperty) ====== - private static final String REMOTE_HOST = System.getProperty("it.remoteHost", "194.87.0.247"); - private static final String REMOTE_USER = System.getProperty("it.remoteUser", "user"); + private static final String REMOTE_HOST = System.getProperty("it.remoteHost", "shineup.me"); + private static final String REMOTE_USER = System.getProperty("it.remoteUser", "player"); - private static final String REMOTE_DIR = System.getProperty("it.remoteDir", "/home/user/docker/shine-server"); + private static final String REMOTE_DIR = System.getProperty("it.remoteDir", "/home/player/SHiNE/shine-server"); private static final String REMOTE_JAR = REMOTE_DIR + "/shine-server.jar"; private static final String REMOTE_DATA = System.getProperty("it.remoteDataDir", REMOTE_DIR + "/data"); diff --git a/VERSION.properties b/VERSION.properties index ab54975..85efee4 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.111 -server.version=1.2.103 +client.version=1.2.112 +server.version=1.2.104 diff --git a/shine-UI/js/pages/registration-draft-keys-view.js b/shine-UI/js/pages/registration-draft-keys-view.js index a6ba325..cb18a05 100644 --- a/shine-UI/js/pages/registration-draft-keys-view.js +++ b/shine-UI/js/pages/registration-draft-keys-view.js @@ -1,6 +1,6 @@ import { renderHeader } from '../components/header.js'; import { state } from '../state.js'; -import { bytesToBase64 } from '../services/crypto-utils.js'; +import { base64ToBytes, bytesToBase58 } from '../services/crypto-utils.js'; import { extractSeed32FromPkcs8B64 } from '../services/device-key-utils.js'; export const pageMeta = { id: 'registration-draft-keys-view', title: 'Сгенерированные ключи', showAppChrome: false }; @@ -17,7 +17,7 @@ function makeSecretField({ label, value }) { row.className = 'inline-input-row'; const input = document.createElement('input'); - input.className = 'input'; + input.className = 'input key-input'; input.type = 'password'; input.readOnly = true; input.value = value; @@ -50,7 +50,7 @@ function makePublicField({ label, value }) { labelEl.textContent = label; const input = document.createElement('input'); - input.className = 'input'; + input.className = 'input key-input'; input.type = 'text'; input.readOnly = true; input.value = value; @@ -82,38 +82,56 @@ export function render({ navigate }) { card.append(warning); // Секрет (root key seed) - let secretB64 = ''; + let secretB58 = ''; try { const rootSeed32 = extractSeed32FromPkcs8B64(keyBundle.rootPair.privatePkcs8B64); - secretB64 = bytesToBase64(rootSeed32); + secretB58 = bytesToBase58(rootSeed32); } catch { - secretB64 = '(не удалось извлечь)'; + secretB58 = '(не удалось извлечь)'; } - card.append(makeSecretField({ label: 'Секрет (root seed, 32 байта)', value: secretB64 })); + card.append(makeSecretField({ label: 'Секрет (root seed, base58, 32 байта)', value: secretB58 })); // Root key const rootSep = document.createElement('p'); rootSep.className = 'field-label'; rootSep.textContent = 'Root key'; card.append(rootSep); - card.append(makePublicField({ label: 'Root — публичный', value: keyBundle.rootPair.publicKeyB64 })); - card.append(makeSecretField({ label: 'Root — приватный (PKCS8)', value: keyBundle.rootPair.privatePkcs8B64 })); + card.append(makePublicField({ + label: 'Root — публичный (base58)', + value: bytesToBase58(base64ToBytes(keyBundle.rootPair.publicKeyB64)), + })); + card.append(makeSecretField({ + label: 'Root — приватный (seed base58, 32 байта)', + value: bytesToBase58(extractSeed32FromPkcs8B64(keyBundle.rootPair.privatePkcs8B64)), + })); // Blockchain key const bchSep = document.createElement('p'); bchSep.className = 'field-label'; bchSep.textContent = 'Blockchain key'; card.append(bchSep); - card.append(makePublicField({ label: 'Blockchain — публичный', value: keyBundle.blockchainPair.publicKeyB64 })); - card.append(makeSecretField({ label: 'Blockchain — приватный (PKCS8)', value: keyBundle.blockchainPair.privatePkcs8B64 })); + card.append(makePublicField({ + label: 'Blockchain — публичный (base58)', + value: bytesToBase58(base64ToBytes(keyBundle.blockchainPair.publicKeyB64)), + })); + card.append(makeSecretField({ + label: 'Blockchain — приватный (seed base58, 32 байта)', + value: bytesToBase58(extractSeed32FromPkcs8B64(keyBundle.blockchainPair.privatePkcs8B64)), + })); // Device key const devSep = document.createElement('p'); devSep.className = 'field-label'; devSep.textContent = 'Device key (= Solana wallet)'; card.append(devSep); - card.append(makePublicField({ label: 'Device — публичный', value: keyBundle.devicePair.publicKeyB64 })); - card.append(makeSecretField({ label: 'Device — приватный (PKCS8)', value: keyBundle.devicePair.privatePkcs8B64 })); + card.append(makePublicField({ + label: 'Device — публичный (base58)', + value: bytesToBase58(base64ToBytes(keyBundle.devicePair.publicKeyB64)), + })); + card.append(makeSecretField({ + label: 'Device — приватный (seed base58, 32 байта)', + value: bytesToBase58(extractSeed32FromPkcs8B64(keyBundle.devicePair.privatePkcs8B64)), + })); } const actions = document.createElement('div'); diff --git a/shine-UI/js/pages/show-keys-view.js b/shine-UI/js/pages/show-keys-view.js index d73f07d..29a1273 100644 --- a/shine-UI/js/pages/show-keys-view.js +++ b/shine-UI/js/pages/show-keys-view.js @@ -1,5 +1,7 @@ import { renderHeader } from '../components/header.js'; import { state } from '../state.js'; +import { bytesToBase58 } from '../services/crypto-utils.js'; +import { extractSeed32FromPkcs8B64 } from '../services/device-key-utils.js'; import { loadEncryptedUserSecrets } from '../services/key-vault.js'; export const pageMeta = { id: 'show-keys-view', title: 'Показать ключи' }; @@ -43,15 +45,15 @@ export function render({ navigate }) { ${label} -
*****
+
*****
`; return row; }; card.append( - renderField('root', 'root key'), - renderField('blockchain', 'blockchain.key'), - renderField('device', 'device key'), + renderField('root', 'root key (base58)'), + renderField('blockchain', 'blockchain.key (base58)'), + renderField('device', 'device key (base58)'), ); const setMissingState = (id) => { @@ -106,9 +108,13 @@ export function render({ navigate }) { state.session.storagePwdInMemory, ); - keys.root = savedKeys.rootKey || ''; - keys.blockchain = savedKeys.blockchainKey || ''; - keys.device = savedKeys.deviceKey || ''; + const rootSeed32 = savedKeys.rootKey ? extractSeed32FromPkcs8B64(savedKeys.rootKey) : null; + const blockchainSeed32 = savedKeys.blockchainKey ? extractSeed32FromPkcs8B64(savedKeys.blockchainKey) : null; + const deviceSeed32 = savedKeys.deviceKey ? extractSeed32FromPkcs8B64(savedKeys.deviceKey) : null; + + keys.root = rootSeed32 ? bytesToBase58(rootSeed32) : ''; + keys.blockchain = blockchainSeed32 ? bytesToBase58(blockchainSeed32) : ''; + keys.device = deviceSeed32 ? bytesToBase58(deviceSeed32) : ''; if (keys.root || keys.blockchain || keys.device) { status.textContent = 'Показаны только ключи, сохранённые на этом устройстве.'; diff --git a/shine-UI/js/services/crypto-utils.js b/shine-UI/js/services/crypto-utils.js index a7f0bc8..a74f00c 100644 --- a/shine-UI/js/services/crypto-utils.js +++ b/shine-UI/js/services/crypto-utils.js @@ -25,6 +25,33 @@ function base64UrlToBase64(value) { return normalized + '='.repeat(padLen); } +const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + +export function bytesToBase58(bytes) { + const input = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes || []); + if (input.length === 0) return ''; + + const digits = []; + for (let i = 0; i < input.length; i += 1) { + let carry = input[i]; + for (let j = 0; j < digits.length; j += 1) { + const value = (digits[j] * 256) + carry; + digits[j] = value % 58; + carry = Math.floor(value / 58); + } + while (carry > 0) { + digits.push(carry % 58); + carry = Math.floor(carry / 58); + } + } + + for (let i = 0; i < input.length && input[i] === 0; i += 1) { + digits.push(0); + } + + return digits.reverse().map((digit) => BASE58_ALPHABET[digit]).join(''); +} + export function randomBase64(byteLen = 32) { const bytes = getCryptoApi().getRandomValues(new Uint8Array(byteLen)); return bytesToBase64(bytes); diff --git a/shine-UI/styles/components.css b/shine-UI/styles/components.css index e532458..2bfd8bb 100644 --- a/shine-UI/styles/components.css +++ b/shine-UI/styles/components.css @@ -1270,6 +1270,17 @@ textarea.input { color: #dce7ff; } +.key-value--compact { + font-size: 11px; + line-height: 1.25; +} + +.key-input { + font-family: "IBM Plex Mono", "Fira Code", monospace; + font-size: 12px; + letter-spacing: 0; +} + .qr-demo { width: 64px; height: 64px;