SHA256
Убрал long-press меню каналов и обновил deploy-проверку sudo
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import qrcode from '../vendor-qrcode-generator.js';
|
||||
|
||||
const TRANSFER_PREFIX = 'shine-key-transfer-v1:';
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
function bytesToBase64Url(bytes) {
|
||||
let binary = '';
|
||||
bytes.forEach((b) => {
|
||||
binary += String.fromCharCode(b);
|
||||
});
|
||||
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
||||
}
|
||||
|
||||
function base64UrlToBytes(value) {
|
||||
const normalized = String(value || '').trim().replace(/-/g, '+').replace(/_/g, '/');
|
||||
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
|
||||
const binary = atob(padded);
|
||||
const out = new Uint8Array(binary.length);
|
||||
for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
export function keyLabel(id) {
|
||||
if (id === 'root') return 'root';
|
||||
if (id === 'blockchain') return 'blockchain';
|
||||
if (id === 'device') return 'device';
|
||||
return id;
|
||||
}
|
||||
|
||||
export function describeTransferKeys(keys = {}) {
|
||||
const out = [];
|
||||
if (keys.deviceKey) out.push('device');
|
||||
if (keys.blockchainKey) out.push('blockchain');
|
||||
if (keys.rootKey) out.push('root');
|
||||
return out;
|
||||
}
|
||||
|
||||
export function makeKeyTransferText({ login, keys }) {
|
||||
const payload = {
|
||||
v: 1,
|
||||
type: 'shine-key-transfer',
|
||||
login: String(login || '').trim(),
|
||||
keys: {
|
||||
deviceKey: String(keys?.deviceKey || ''),
|
||||
blockchainKey: String(keys?.blockchainKey || ''),
|
||||
rootKey: String(keys?.rootKey || ''),
|
||||
},
|
||||
createdAtMs: Date.now(),
|
||||
};
|
||||
const json = JSON.stringify(payload);
|
||||
return `${TRANSFER_PREFIX}${bytesToBase64Url(encoder.encode(json))}`;
|
||||
}
|
||||
|
||||
export function parseKeyTransferText(text) {
|
||||
const raw = String(text || '').trim();
|
||||
if (!raw.startsWith(TRANSFER_PREFIX)) {
|
||||
throw new Error('Это не QR-код переноса ключей SHiNE');
|
||||
}
|
||||
const json = decoder.decode(base64UrlToBytes(raw.slice(TRANSFER_PREFIX.length)));
|
||||
const payload = JSON.parse(json);
|
||||
if (payload?.v !== 1 || payload?.type !== 'shine-key-transfer') {
|
||||
throw new Error('Неподдерживаемый формат QR-кода');
|
||||
}
|
||||
const login = String(payload.login || '').trim();
|
||||
if (!login) throw new Error('В QR-коде нет логина');
|
||||
const keys = payload.keys && typeof payload.keys === 'object' ? payload.keys : {};
|
||||
if (!keys.deviceKey && !keys.blockchainKey && !keys.rootKey) {
|
||||
throw new Error('В QR-коде нет ключей');
|
||||
}
|
||||
return {
|
||||
login,
|
||||
keys: {
|
||||
deviceKey: String(keys.deviceKey || ''),
|
||||
blockchainKey: String(keys.blockchainKey || ''),
|
||||
rootKey: String(keys.rootKey || ''),
|
||||
},
|
||||
keyTypes: describeTransferKeys(keys),
|
||||
};
|
||||
}
|
||||
|
||||
export function renderQrSvg(text, { cellSize = 4, margin = 4 } = {}) {
|
||||
const qr = qrcode(0, 'L');
|
||||
qr.addData(String(text || ''), 'Byte');
|
||||
qr.make();
|
||||
return qr.createSvgTag(cellSize, margin);
|
||||
}
|
||||
Reference in New Issue
Block a user