Files
bare-operating-system/packages/bare-os-booter/lib/hdms-share-offer.js
T
2026-04-05 22:45:21 -04:00

108 lines
3.0 KiB
JavaScript

/**
* Autopass payload for HDMS drive sharing (invite → pair → mount).
* Kept separate from hdms-manager.js for small, Node-testable surface.
*/
import b4a from 'b4a'
import idEnc from 'hypercore-id-encoding'
/** Autopass record key: read-only replica offer (public key only). */
export const HDMS_AUTOPASS_SHARE_KEY = 'bare-os-hdms/pending-share'
/** Autopass record key: read/write replica (public key + writer secret). Legacy peers ignore this key. */
export const HDMS_AUTOPASS_SHARE_RW_KEY = 'bare-os-hdms/pending-share-rw'
/** Expected hex length for a Hypercore Ed25519 secret key (64 bytes). */
export const WRITER_SECRET_HEX_LEN = 128
/**
* @param {string} hex
* @returns {string} lowercase hex
*/
export function normalizeWriterSecretHex(hex) {
if (typeof hex !== 'string') throw new Error('Invalid writer secret')
const h = hex.trim().toLowerCase()
if (!/^[0-9a-f]{128}$/.test(h)) {
throw new Error('writerSecretHex must be 128 hex chars (64 bytes)')
}
return h
}
/**
* @param {string} hex
* @returns {Uint8Array}
*/
export function writerSecretBytesFromHex(hex) {
return b4a.from(normalizeWriterSecretHex(hex), 'hex')
}
/** @param {{ remove: (k: string) => Promise<unknown> }} ap */
export async function removeBothHdmsShareKeys(ap) {
for (const k of [HDMS_AUTOPASS_SHARE_KEY, HDMS_AUTOPASS_SHARE_RW_KEY]) {
try {
await ap.remove(k)
} catch {
/* no prior offer */
}
}
}
/** @param {{ value?: unknown } | null | undefined} offer */
export function decodeShareOffer(offer) {
if (!offer || offer.value == null) return null
const v = offer.value
const raw =
typeof v === 'string' ? v : b4a.toString(/** @type {Uint8Array} */ (v))
try {
const j = JSON.parse(raw)
if (
j &&
typeof j.key === 'string' &&
typeof j.label === 'string' &&
j.key.length > 0
) {
return { label: j.label, key: j.key }
}
} catch {
/* ignore */
}
return null
}
/**
* RW payload uses `key` = Hyperdrive public key (manifest id, z32) for discovery/open,
* and `signerKey` = metadata writer Ed25519 public key (z32) matching `writerSecretHex`.
* @param {{ value?: unknown } | null | undefined} offer
* @returns {{ label: string, key: string, signerKey: string, writerSecretHex: string } | null}
*/
export function decodeRwShareOffer(offer) {
if (!offer || offer.value == null) return null
const v = offer.value
const raw =
typeof v === 'string' ? v : b4a.toString(/** @type {Uint8Array} */ (v))
try {
const j = JSON.parse(raw)
if (
j &&
typeof j.key === 'string' &&
typeof j.label === 'string' &&
typeof j.signerKey === 'string' &&
typeof j.writerSecretHex === 'string' &&
j.key.length > 0 &&
j.signerKey.length > 0
) {
idEnc.decode(j.signerKey)
idEnc.decode(j.key)
return {
label: j.label,
key: j.key,
signerKey: j.signerKey,
writerSecretHex: normalizeWriterSecretHex(j.writerSecretHex)
}
}
} catch {
/* ignore */
}
return null
}