@radixdlt/rola
Version:
Radix TypeScript ROLA library
247 lines (235 loc) • 9.93 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/rola.ts
var rola_exports = {};
__export(rola_exports, {
Rola: () => Rola
});
module.exports = __toCommonJS(rola_exports);
var import_neverthrow5 = require("neverthrow");
// src/helpers/create-signature-message.ts
var import_buffer2 = require("buffer");
// src/crypto/blake2b.ts
var import_neverthrow = require("neverthrow");
var import_blakejs = __toESM(require("blakejs"), 1);
var import_buffer = require("buffer");
var toArrayBuffer = (buffer) => {
const arrayBuffer = new ArrayBuffer(buffer.length);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < buffer.length; ++i) {
view[i] = buffer[i];
}
return arrayBuffer;
};
var bufferToUnit8Array = (buffer) => new Uint8Array(toArrayBuffer(buffer));
var blake2b = (input) => {
try {
return (0, import_neverthrow.ok)(import_blakejs.default.blake2bHex(bufferToUnit8Array(input), void 0, 32)).map(
(hex) => import_buffer.Buffer.from(hex, "hex")
);
} catch (error) {
return (0, import_neverthrow.err)(error);
}
};
// src/helpers/create-signature-message.ts
var createSignatureMessage = ({
challenge,
dAppDefinitionAddress,
origin
}) => {
const prefix = import_buffer2.Buffer.from("R", "ascii");
const lengthOfDappDefAddress = dAppDefinitionAddress.length;
const lengthOfDappDefAddressBuffer = import_buffer2.Buffer.from(
lengthOfDappDefAddress.toString(16),
"hex"
);
const dappDefAddressBuffer = import_buffer2.Buffer.from(dAppDefinitionAddress, "utf-8");
const originBuffer = import_buffer2.Buffer.from(origin, "utf-8");
const challengeBuffer = import_buffer2.Buffer.from(challenge, "hex");
const messageBuffer = import_buffer2.Buffer.concat([
prefix,
challengeBuffer,
lengthOfDappDefAddressBuffer,
dappDefAddressBuffer,
originBuffer
]);
return blake2b(messageBuffer).map((hash) => import_buffer2.Buffer.from(hash).toString("hex")).mapErr((jsError) => ({ reason: "couldNotHashMessage", jsError }));
};
// src/helpers/verify-proof.ts
var import_neverthrow2 = require("neverthrow");
var import_secp256k1 = require("@noble/curves/secp256k1");
var import_ed25519 = require("@noble/curves/ed25519");
var supportedCurves = /* @__PURE__ */ new Set(["curve25519", "secp256k1"]);
var verifyProofFactory = (input) => (signatureMessageHex) => {
const isSupportedCurve = supportedCurves.has(input.proof.curve);
if (!isSupportedCurve)
return (0, import_neverthrow2.err)({ reason: "unsupportedCurve" });
try {
let isValid = false;
if (input.proof.curve === "curve25519") {
isValid = import_ed25519.ed25519.verify(
input.proof.signature,
signatureMessageHex,
input.proof.publicKey
);
} else {
const signature = input.proof.signature.slice(2);
isValid = import_secp256k1.secp256k1.verify(
signature,
signatureMessageHex,
input.proof.publicKey
);
}
return isValid ? (0, import_neverthrow2.ok)(void 0) : (0, import_neverthrow2.err)({ reason: "invalidSignature" });
} catch (error) {
return (0, import_neverthrow2.err)({ reason: "invalidPublicKey", jsError: error });
}
};
// src/helpers/derive-address-from-public-key.ts
var import_radix_engine_toolkit = require("@radixdlt/radix-engine-toolkit");
var import_neverthrow3 = require("neverthrow");
// src/helpers/typed-error.ts
var typedError = (error) => error;
// src/helpers/derive-address-from-public-key.ts
var deriveVirtualIdentityAddress = (publicKey, networkId) => import_neverthrow3.ResultAsync.fromPromise(
import_radix_engine_toolkit.RadixEngineToolkit.Derive.virtualIdentityAddressFromPublicKey(
new import_radix_engine_toolkit.PublicKey.Ed25519(publicKey),
networkId
),
typedError
);
var deriveVirtualEddsaEd25519AccountAddress = (publicKey, networkId) => import_neverthrow3.ResultAsync.fromPromise(
import_radix_engine_toolkit.RadixEngineToolkit.Derive.virtualAccountAddressFromPublicKey(
new import_radix_engine_toolkit.PublicKey.Ed25519(publicKey),
networkId
),
typedError
);
var deriveVirtualEcdsaSecp256k1AccountAddress = (publicKey, networkId) => import_neverthrow3.ResultAsync.fromPromise(
import_radix_engine_toolkit.RadixEngineToolkit.Derive.virtualAccountAddressFromPublicKey(
new import_radix_engine_toolkit.PublicKey.Secp256k1(publicKey),
networkId
),
typedError
);
var deriveVirtualAddress = (signedChallenge, networkId) => {
if (signedChallenge.type === "persona")
return deriveVirtualIdentityAddress(
signedChallenge.proof.publicKey,
networkId
);
else if (signedChallenge.type === "account" && signedChallenge.proof.curve === "curve25519")
return deriveVirtualEddsaEd25519AccountAddress(
signedChallenge.proof.publicKey,
networkId
);
else if (signedChallenge.type === "account" && signedChallenge.proof.curve === "secp256k1")
return deriveVirtualEcdsaSecp256k1AccountAddress(
signedChallenge.proof.publicKey,
networkId
);
return (0, import_neverthrow3.errAsync)(new Error("Could not derive virtual address"));
};
// src/helpers/create-public-key-hash.ts
var import_buffer3 = require("buffer");
var createPublicKeyHash = (publicKey) => blake2b(import_buffer3.Buffer.from(publicKey, "hex")).map((hash) => hash.subarray(-29)).map((hash) => import_buffer3.Buffer.from(hash).toString("hex"));
// src/gateway.ts
var import_babylon_gateway_api_sdk = require("@radixdlt/babylon-gateway-api-sdk");
var import_neverthrow4 = require("neverthrow");
var GatewayService = (input) => {
var _a;
const { networkId, applicationName } = input;
const config = import_babylon_gateway_api_sdk.RadixNetworkConfigById[networkId];
if (!config)
throw new Error(`Network ${networkId} not found`);
const { state } = (_a = input.gatewayApiClient) != null ? _a : import_babylon_gateway_api_sdk.GatewayApiClient.initialize({
basePath: config.gatewayUrl,
applicationName
});
const getEntityDetails = (address) => import_neverthrow4.ResultAsync.fromPromise(
state.getEntityDetailsVaultAggregated(address),
typedError
);
return {
getEntityOwnerKeys: (address) => getEntityDetails(address).map(
(response) => {
var _a2, _b, _c;
return (_c = (_b = (_a2 = response == null ? void 0 : response.metadata) == null ? void 0 : _a2.items.find((item) => item.key === "owner_keys")) == null ? void 0 : _b.value.raw_hex) != null ? _c : "";
}
)
};
};
// src/rola.ts
if (!globalThis.self)
globalThis.self = globalThis;
var Rola = (input) => {
const { expectedOrigin, dAppDefinitionAddress, networkId, applicationName } = input;
const gatewayService = GatewayService({
networkId,
applicationName,
gatewayApiClient: input.gatewayApiClient
});
const verifySignedChallenge = (signedChallenge) => {
const result = createPublicKeyHash(signedChallenge.proof.publicKey);
if (result.isErr())
return (0, import_neverthrow5.errAsync)({ reason: "couldNotHashPublicKey" });
const hashedPublicKey = result.value;
const verifyProof = verifyProofFactory(signedChallenge);
const getDerivedAddress = () => deriveVirtualAddress(signedChallenge, networkId).mapErr((jsError) => ({
reason: "couldNotDeriveAddressFromPublicKey",
jsError
}));
const queryLedger = () => gatewayService.getEntityOwnerKeys(signedChallenge.address).mapErr((jsError) => ({
reason: "couldNotVerifyPublicKeyOnLedger",
jsError
})).map((ownerKeys) => ({
ownerKeysMatchesProvidedPublicKey: ownerKeys.toUpperCase().includes(hashedPublicKey.toUpperCase()),
ownerKeysSet: !!ownerKeys
}));
const deriveAddressFromPublicKeyAndQueryLedger = () => import_neverthrow5.ResultAsync.combine([getDerivedAddress(), queryLedger()]);
return createSignatureMessage({
dAppDefinitionAddress,
origin: expectedOrigin,
challenge: signedChallenge.challenge
}).andThen(verifyProof).asyncAndThen(deriveAddressFromPublicKeyAndQueryLedger).andThen(
([
derivedAddress,
{ ownerKeysMatchesProvidedPublicKey, ownerKeysSet }
]) => {
const derivedAddressMatchesPublicKey = !ownerKeysSet && derivedAddress === signedChallenge.address;
return ownerKeysMatchesProvidedPublicKey || derivedAddressMatchesPublicKey ? (0, import_neverthrow5.ok)(void 0) : (0, import_neverthrow5.err)({ reason: "invalidPublicKey" });
}
);
};
return { verifySignedChallenge };
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Rola
});