179 lines
6.0 KiB
JavaScript
179 lines
6.0 KiB
JavaScript
|
var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
|
||
|
function adopt(value) {
|
||
|
return value instanceof P ? value : new P(function (resolve) {
|
||
|
resolve(value);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||
|
function fulfilled(value) {
|
||
|
try {
|
||
|
step(generator.next(value));
|
||
|
} catch (e) {
|
||
|
reject(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function rejected(value) {
|
||
|
try {
|
||
|
step(generator["throw"](value));
|
||
|
} catch (e) {
|
||
|
reject(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function step(result) {
|
||
|
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
||
|
}
|
||
|
|
||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||
|
});
|
||
|
};
|
||
|
|
||
|
import { bytesAtOffset, bytesEqual, flexBytesAtOffset } from "../utils/bytes.js";
|
||
|
import { bmtHash } from "./bmt.js";
|
||
|
import { recoverAddress, sign } from "./signer.js";
|
||
|
import { keccak256Hash } from "../utils/hash.js";
|
||
|
import { SPAN_SIZE } from "./span.js";
|
||
|
import { serializeBytes } from "./serialize.js";
|
||
|
import { BeeError } from "../utils/error.js";
|
||
|
import { makeContentAddressedChunk, MAX_PAYLOAD_SIZE, MIN_PAYLOAD_SIZE, assertValidChunkData } from "./cac.js";
|
||
|
import { bytesToHex } from "../utils/hex.js";
|
||
|
import * as socAPI from "../modules/soc.js";
|
||
|
import * as chunkAPI from "../modules/chunk.js";
|
||
|
import { assertAddress } from "../utils/type.js";
|
||
|
const IDENTIFIER_SIZE = 32;
|
||
|
const SIGNATURE_SIZE = 65;
|
||
|
const SOC_IDENTIFIER_OFFSET = 0;
|
||
|
const SOC_SIGNATURE_OFFSET = SOC_IDENTIFIER_OFFSET + IDENTIFIER_SIZE;
|
||
|
const SOC_SPAN_OFFSET = SOC_SIGNATURE_OFFSET + SIGNATURE_SIZE;
|
||
|
const SOC_PAYLOAD_OFFSET = SOC_SPAN_OFFSET + SPAN_SIZE;
|
||
|
|
||
|
function recoverChunkOwner(data) {
|
||
|
const cacData = data.slice(SOC_SPAN_OFFSET);
|
||
|
const chunkAddress = bmtHash(cacData);
|
||
|
const signature = bytesAtOffset(data, SOC_SIGNATURE_OFFSET, SIGNATURE_SIZE);
|
||
|
const identifier = bytesAtOffset(data, SOC_IDENTIFIER_OFFSET, IDENTIFIER_SIZE);
|
||
|
const digest = keccak256Hash(identifier, chunkAddress);
|
||
|
const ownerAddress = recoverAddress(signature, digest);
|
||
|
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) {
|
||
|
const ownerAddress = recoverChunkOwner(data);
|
||
|
const identifier = bytesAtOffset(data, SOC_IDENTIFIER_OFFSET, IDENTIFIER_SIZE);
|
||
|
const socAddress = keccak256Hash(identifier, ownerAddress);
|
||
|
|
||
|
if (!bytesEqual(address, socAddress)) {
|
||
|
throw new BeeError('SOC Data does not match given address!');
|
||
|
}
|
||
|
|
||
|
const signature = () => bytesAtOffset(data, SOC_SIGNATURE_OFFSET, SIGNATURE_SIZE);
|
||
|
|
||
|
const span = () => bytesAtOffset(data, SOC_SPAN_OFFSET, SPAN_SIZE);
|
||
|
|
||
|
const payload = () => flexBytesAtOffset(data, SOC_PAYLOAD_OFFSET, MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE);
|
||
|
|
||
|
return {
|
||
|
data,
|
||
|
identifier: () => identifier,
|
||
|
signature,
|
||
|
span,
|
||
|
payload,
|
||
|
address: () => socAddress,
|
||
|
owner: () => ownerAddress
|
||
|
};
|
||
|
}
|
||
|
export function makeSOCAddress(identifier, address) {
|
||
|
return keccak256Hash(identifier, address);
|
||
|
}
|
||
|
/**
|
||
|
* 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 singer interface for signing the chunk
|
||
|
*/
|
||
|
|
||
|
export function makeSingleOwnerChunk(chunk, identifier, signer) {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
const chunkAddress = chunk.address();
|
||
|
assertValidChunkData(chunk.data, chunkAddress);
|
||
|
const digest = keccak256Hash(identifier, chunkAddress);
|
||
|
const signature = yield sign(signer, digest);
|
||
|
const data = serializeBytes(identifier, signature, chunk.span(), chunk.payload());
|
||
|
const address = makeSOCAddress(identifier, signer.address);
|
||
|
return {
|
||
|
data,
|
||
|
identifier: () => identifier,
|
||
|
signature: () => signature,
|
||
|
span: () => chunk.span(),
|
||
|
payload: () => chunk.payload(),
|
||
|
address: () => address,
|
||
|
owner: () => signer.address
|
||
|
};
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Helper function to upload a chunk.
|
||
|
*
|
||
|
* It uses the Chunk API and calculates the address before uploading.
|
||
|
*
|
||
|
* @param ky Ky instance
|
||
|
* @param chunk A chunk object
|
||
|
* @param postageBatchId Postage BatchId that will be assigned to uploaded data
|
||
|
* @param options Upload options
|
||
|
*/
|
||
|
|
||
|
export function uploadSingleOwnerChunk(ky, chunk, postageBatchId, options) {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
const owner = bytesToHex(chunk.owner());
|
||
|
const identifier = bytesToHex(chunk.identifier());
|
||
|
const signature = bytesToHex(chunk.signature());
|
||
|
const data = serializeBytes(chunk.span(), chunk.payload());
|
||
|
return socAPI.upload(ky, owner, identifier, signature, data, postageBatchId, options);
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Helper function to create and upload SOC.
|
||
|
*
|
||
|
* @param ky Ky instance
|
||
|
* @param signer The singer interface for signing the chunk
|
||
|
* @param postageBatchId
|
||
|
* @param identifier The identifier of the chunk
|
||
|
* @param data The chunk data
|
||
|
* @param options
|
||
|
*/
|
||
|
|
||
|
export function uploadSingleOwnerChunkData(ky, signer, postageBatchId, identifier, data, options) {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
assertAddress(postageBatchId);
|
||
|
const cac = makeContentAddressedChunk(data);
|
||
|
const soc = yield makeSingleOwnerChunk(cac, identifier, signer);
|
||
|
return uploadSingleOwnerChunk(ky, soc, postageBatchId, options);
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Helper function to download SOC.
|
||
|
*
|
||
|
* @param url The url of the Bee service
|
||
|
* @param ownerAddress The singer interface for signing the chunk
|
||
|
* @param identifier The identifier of the chunk
|
||
|
*/
|
||
|
|
||
|
export function downloadSingleOwnerChunk(ky, ownerAddress, identifier) {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
const address = makeSOCAddress(identifier, ownerAddress);
|
||
|
const data = yield chunkAPI.download(ky, bytesToHex(address));
|
||
|
return makeSingleOwnerChunkFromData(data, address);
|
||
|
});
|
||
|
}
|