/
raiden
/
obsidian-git-encrypt
Обзор
Документация
Войти
/
raiden
/
obsidian-git-encrypt
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/crypto/encoding.ts
78 строк
2 KB
Robert Kuzhin
feat: add encrypted mirror and manifest store
09 авг 2026, 10:06
09 авг 2026, 10:06
7f1b7fe
Код
Авторство
О чём код?
import { FORMAT_VERSION } from "./constants.js"; const encoder = new TextEncoder(); const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u; export function encodeUtf8(value: string): Uint8Array { return encoder.encode(value); } export function concatBytes(...parts: readonly Uint8Array[]): Uint8Array { const length = parts.reduce((total, part) => total + part.length, 0); const result = new Uint8Array(length); let offset = 0; for (const part of parts) { result.set(part, offset); offset += part.length; } return result; } function encodeField(value: string): Uint8Array { const bytes = encodeUtf8(value); if (bytes.length > 0xffff) { throw new RangeError("Authenticated context field is too long"); } const result = new Uint8Array(2 + bytes.length); new DataView(result.buffer).setUint16(0, bytes.length, false); result.set(bytes, 2); return result; } export function buildAssociatedData( vaultId: string, objectType: "file" | "manifest" | "vault-key", fileId: string, ): Uint8Array { assertUuid(vaultId, "vaultId"); if (objectType === "file") { assertUuid(fileId, "fileId"); } else if (fileId !== objectType) { throw new TypeError(`${objectType} payload must use its canonical identity`); } return concatBytes( new Uint8Array([FORMAT_VERSION]), encodeField(vaultId), encodeField(objectType), encodeField(fileId), ); } export function buildObjectKeyInfo(fileId: string): Uint8Array { assertUuid(fileId, "fileId"); return concatBytes(encodeField("obsidian-encrypted-git/file-key/v1"), encodeField(fileId)); } export function buildManifestKeyInfo(): Uint8Array { return encodeField("obsidian-encrypted-git/manifest-key/v1"); } export function assertUuid(value: string, fieldName: string): void { if (!UUID_PATTERN.test(value)) { throw new TypeError(`${fieldName} must be a lowercase UUIDv4`); } } export function randomUuid(random: Uint8Array): string { if (random.length !== 16) { throw new RangeError("UUID input must contain 16 bytes"); } const bytes = new Uint8Array(random); bytes[6] = (bytes[6]! & 0x0f) | 0x40; bytes[8] = (bytes[8]! & 0x3f) | 0x80; const hex = [...bytes].map((value) => value.toString(16).padStart(2, "0")).join(""); return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; }