UNPKG

@web5/agent

Version:
120 lines 6.08 kB
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 { Sha256, CryptoUtils } from '@web5/crypto'; import { concatenateUrl } from './utils.js'; import { Convert } from '@web5/common'; /** * A client for registering tenants with a DWN. */ export class DwnRegistrar { /** * Registers a new tenant with the given DWN. * NOTE: Assumes the user has already accepted the terms of service. * NOTE: Currently the DWN Server from `dwn-server` does not require user signature. * TODO: bring in types from `dwn-server`. */ static registerTenant(dwnEndpoint, did) { return __awaiter(this, void 0, void 0, function* () { const registrationEndpoint = concatenateUrl(dwnEndpoint, 'registration'); const termsOfUseEndpoint = concatenateUrl(registrationEndpoint, 'terms-of-service'); const proofOfWorkEndpoint = concatenateUrl(registrationEndpoint, 'proof-of-work'); // fetch the terms-of-service const termsOfServiceGetResponse = yield fetch(termsOfUseEndpoint, { method: 'GET', }); if (termsOfServiceGetResponse.status !== 200) { const statusCode = termsOfServiceGetResponse.status; const statusText = termsOfServiceGetResponse.statusText; const errorText = yield termsOfServiceGetResponse.text(); throw new Error(`Failed fetching terms-of-service: ${statusCode} ${statusText}: ${errorText}`); } const termsOfServiceFetched = yield termsOfServiceGetResponse.text(); // fetch the proof-of-work challenge const proofOfWorkChallengeGetResponse = yield fetch(proofOfWorkEndpoint, { method: 'GET', }); const { challengeNonce, maximumAllowedHashValue } = yield proofOfWorkChallengeGetResponse.json(); // create registration data based on the hash of the terms-of-service and the DID const registrationData = { did, termsOfServiceHash: yield DwnRegistrar.hashAsHexString(termsOfServiceFetched), }; // compute the proof-of-work response nonce based on the the proof-of-work challenge and the registration data. const responseNonce = yield DwnRegistrar.findQualifiedResponseNonce({ challengeNonce, maximumAllowedHashValue, requestData: JSON.stringify(registrationData), }); // send the registration request to the server const registrationRequest = { registrationData, proofOfWork: { challengeNonce, responseNonce, }, }; const registrationResponse = yield fetch(registrationEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(registrationRequest), }); if (registrationResponse.status !== 200) { const statusCode = registrationResponse.status; const statusText = registrationResponse.statusText; const errorText = yield registrationResponse.text(); throw new Error(`Registration failed: ${statusCode} ${statusText}: ${errorText}`); } }); } /** * Computes the SHA-256 hash of the given array of strings. */ static hashAsHexString(input) { return __awaiter(this, void 0, void 0, function* () { const hashAsBytes = yield Sha256.digest({ data: Convert.string(input).toUint8Array() }); const hashAsHex = Convert.uint8Array(hashAsBytes).toHex(); return hashAsHex; }); } /** * Finds a response nonce that qualifies the difficulty requirement for the given proof-of-work challenge and request data. */ static findQualifiedResponseNonce(input) { return __awaiter(this, void 0, void 0, function* () { const startTime = Date.now(); const { maximumAllowedHashValue, challengeNonce, requestData } = input; const maximumAllowedHashValueAsBigInt = BigInt(`0x${maximumAllowedHashValue}`); let iterations = 1; let responseNonce; let qualifiedSolutionNonceFound = false; do { responseNonce = yield this.generateNonce(); const computedHash = yield DwnRegistrar.hashAsHexString(challengeNonce + responseNonce + requestData); const computedHashAsBigInt = BigInt(`0x${computedHash}`); qualifiedSolutionNonceFound = computedHashAsBigInt <= maximumAllowedHashValueAsBigInt; iterations++; } while (!qualifiedSolutionNonceFound); // Log final/successful iteration. console.log(`iterations: ${iterations}, time lapsed: ${Date.now() - startTime} ms`); return responseNonce; }); } /** * Generates 32 random bytes expressed as a HEX string. */ static generateNonce() { return __awaiter(this, void 0, void 0, function* () { const randomBytes = CryptoUtils.randomBytes(32); const hexString = Convert.uint8Array(randomBytes).toHex().toUpperCase(); return hexString; }); } } //# sourceMappingURL=dwn-registrar.js.map