UNPKG

@ethersphere/bee-js

Version:
129 lines 5.48 kB
import { Binary } from 'cafe-utility'; import * as chunkAPI from "../modules/chunk.js"; import * as socAPI from "../modules/soc.js"; import { Bytes } from "../utils/bytes.js"; import { BeeError } from "../utils/error.js"; import { EthAddress, Identifier, PrivateKey, Reference, Signature, Span } from "../utils/typed-bytes.js"; import { calculateChunkAddress } from "./bmt.js"; import { asContentAddressedChunk, makeContentAddressedChunk } from "./cac.js"; const SOC_SIGNATURE_OFFSET = Identifier.LENGTH; const SOC_SPAN_OFFSET = SOC_SIGNATURE_OFFSET + Signature.LENGTH; const SOC_PAYLOAD_OFFSET = SOC_SPAN_OFFSET + Span.LENGTH; function recoverChunkOwner(data) { const cacData = data.slice(SOC_SPAN_OFFSET); const chunkAddress = calculateChunkAddress(cacData); const signature = Signature.fromSlice(data, SOC_SIGNATURE_OFFSET); const identifier = Bytes.fromSlice(data, 0, Identifier.LENGTH); const digest = Binary.concatBytes(identifier.toUint8Array(), chunkAddress.toUint8Array()); const ownerAddress = signature.recoverPublicKey(digest).address(); return ownerAddress; } /** * Verifies if the data is a valid single owner chunk * * @param data The chunk data * @param address The address of the single owner chunk * * @returns a single owner chunk or throws error */ export function makeSingleOwnerChunkFromData(data, address) { data = data instanceof Bytes ? data.toUint8Array() : data; address = new Reference(address); const ownerAddress = recoverChunkOwner(data); const identifier = Bytes.fromSlice(data, 0, Identifier.LENGTH); const socAddress = new Reference(Binary.keccak256(Binary.concatBytes(identifier.toUint8Array(), ownerAddress.toUint8Array()))); if (!Binary.equals(address.toUint8Array(), socAddress.toUint8Array())) { throw new BeeError('SOC Data does not match given address!'); } const signature = Signature.fromSlice(data, SOC_SIGNATURE_OFFSET); const span = Span.fromSlice(data, SOC_SPAN_OFFSET); const payload = Bytes.fromSlice(data, SOC_PAYLOAD_OFFSET); return { data, identifier, signature, span, payload, address: socAddress, owner: ownerAddress }; } export function makeSOCAddress(identifier, address) { return new Reference(Binary.keccak256(Binary.concatBytes(identifier.toUint8Array(), address.toUint8Array()))); } /** * Creates a single owner chunk object * * @param chunk A chunk object used for the span and payload * @param identifier The identifier of the chunk * @param signer The signer interface for signing the chunk */ export function makeSingleOwnerChunk(chunk, identifier, signer) { identifier = new Identifier(identifier); signer = new PrivateKey(signer); const address = makeSOCAddress(identifier, signer.publicKey().address()); const signature = signer.sign(Binary.concatBytes(identifier.toUint8Array(), chunk.address.toUint8Array())); const data = Binary.concatBytes(identifier.toUint8Array(), signature.toUint8Array(), chunk.data); const span = Span.fromSlice(chunk.data, 0); const payload = Bytes.fromSlice(chunk.data, Span.LENGTH); return { data, identifier, signature, span, payload, address, owner: signer.publicKey().address() }; } /** * Helper function to upload a chunk. * * It uses the Chunk API and calculates the address before uploading. * * @param requestOptions Options for making requests * @param chunk A chunk object * @param stamp Postage BatchId that will be assigned to uploaded data * @param options Upload options */ export async function uploadSingleOwnerChunk(requestOptions, chunk, stamp, options) { const data = Binary.concatBytes(chunk.span.toUint8Array(), chunk.payload.toUint8Array()); return socAPI.upload(requestOptions, chunk.owner, chunk.identifier, chunk.signature, data, stamp, options); } /** * Helper function to create and upload SOC. * * @param requestOptions Options for making requests * @param signer The signer interface for signing the chunk * @param postageBatchId * @param identifier The identifier of the chunk * @param data The chunk data * @param options */ export async function uploadSingleOwnerChunkData(requestOptions, signer, stamp, identifier, data, options) { signer = new PrivateKey(signer); identifier = new Identifier(identifier); const cac = makeContentAddressedChunk(data); const soc = makeSingleOwnerChunk(cac, identifier, signer); return uploadSingleOwnerChunk(requestOptions, soc, stamp, options); } export async function uploadSingleOwnerChunkWithWrappedChunk(requestOptions, signer, stamp, identifier, rootChunk, options) { signer = new PrivateKey(signer); identifier = new Identifier(identifier); const soc = makeSingleOwnerChunk(asContentAddressedChunk(rootChunk), identifier, signer); return uploadSingleOwnerChunk(requestOptions, soc, stamp, options); } /** * Helper function to download SOC. * * @param url The url of the Bee service * @param ownerAddress The signer interface for signing the chunk * @param identifier The identifier of the chunk */ export async function downloadSingleOwnerChunk(requestOptions, ownerAddress, identifier) { identifier = new Identifier(identifier); ownerAddress = new EthAddress(ownerAddress); const address = makeSOCAddress(identifier, ownerAddress); const cac = await chunkAPI.download(requestOptions, address.toHex()); return makeSingleOwnerChunkFromData(cac, address); }