rpc-client/src/util.ts

94 lines
2.3 KiB
TypeScript

// @ts-ignore
import stringify from "json-stringify-deterministic";
import type { RPCRequest, RPCResponse } from "@lumeweb/relay-types";
// @ts-ignore
import crypto from "hypercore-crypto";
import b4a from "b4a";
export function isPromise(obj: Promise<any>) {
return (
!!obj &&
(typeof obj === "object" || typeof obj === "function") &&
typeof obj.then === "function"
);
}
/*
Forked from https://github.com/hughsk/flat
*/
export function flatten(target: any, opts: any = {}): any[] {
opts = opts || {};
const delimiter = opts.delimiter || ".";
const maxDepth = opts.maxDepth;
const transformKey =
opts.transformKey || ((key: any) => (isNaN(parseInt(key)) ? key : ""));
const output: any[] = [];
function step(object: any, prev?: any, currentDepth?: any) {
currentDepth = currentDepth || 1;
if (!Array.isArray(object)) {
object = Object.keys(object ?? {});
}
object.forEach(function (key: any) {
const value = object[key];
const isarray = opts.safe && Array.isArray(value);
const type = Object.prototype.toString.call(value);
const isbuffer = b4a.isBuffer(value);
const isobject = type === "[object Object]" || type === "[object Array]";
const newKey = prev
? prev + delimiter + transformKey(key)
: transformKey(key);
if (
!isarray &&
!isbuffer &&
isobject &&
Object.keys(value).length &&
(!opts.maxDepth || currentDepth < maxDepth)
) {
return step(value, newKey, currentDepth + 1);
}
output.push(`${newKey}=${value}`);
});
}
step(target);
return output;
}
export function validateResponse(
relay: Buffer,
response: RPCResponse,
timestamped = false
): boolean {
const field = response.signedField || "data";
// @ts-ignore
const data = response[field];
let json = data;
if (typeof json !== "string") {
json = stringify(json);
}
const updated = response.updated as number;
if (timestamped && updated) {
json = updated.toString() + json;
}
return !!crypto.verify(
b4a.from(json),
b4a.from(response.signature as string, "hex"),
relay
);
}
export function validateTimestampedResponse(
relay: Buffer,
response: RPCResponse
): boolean {
return validateResponse(relay, response, true);
}