108 lines
3.0 KiB
JavaScript
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
|
|
}
|