Skip to content

Commit

Permalink
feat(header): add support for x-seda-json-path
Browse files Browse the repository at this point in the history
  • Loading branch information
FranklinWaller committed Aug 21, 2024
1 parent 63b0a2e commit 1a35994
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 27 deletions.
5 changes: 2 additions & 3 deletions workspace/data-proxy-sdk/src/data-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,8 @@ export class DataProxy {
*
* @param data
*/
signData(data: unknown): SignedData {
const valueToSign = JSON.stringify(data);
const signResult = this.sign(Buffer.from(valueToSign));
signData(data: string): SignedData {
const signResult = this.sign(Buffer.from(data));

return {
publicKey: this.publicKey.toString("hex"),
Expand Down
2 changes: 1 addition & 1 deletion workspace/data-proxy/src/cli/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import {
PRIVATE_KEY_ENV_KEY,
SERVER_PORT,
} from "../constants";
import logger from "../logger";
import { startProxyServer } from "../proxy-server";
import { tryAsync, trySync } from "../utils/try";
import { loadPrivateKey } from "./utils/private-key";
import logger from "../logger";

export const runCommand = new Command("run")
.description("Run the Data Proxy node")
Expand Down
1 change: 1 addition & 0 deletions workspace/data-proxy/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const DEFAULT_ENVIRONMENT: Environment =
export const PROOF_HEADER_KEY = "x-seda-proof";
export const SIGNATURE_HEADER_KEY = "x-seda-signature";
export const PUBLIC_KEY_HEADER_KEY = "x-seda-publickey";
export const JSON_PATH_HEADER_KEY = "x-seda-json-path";

export const PRIVATE_KEY_ENV_KEY = "SEDA_DATA_PROXY_PRIVATE_KEY";
export const PRIVATE_KEY = process.env[PRIVATE_KEY_ENV_KEY];
Expand Down
60 changes: 40 additions & 20 deletions workspace/data-proxy/src/proxy-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Maybe } from "true-myth";
import { type Config, getHttpMethods } from "./config-parser";
import {
DEFAULT_PROXY_ROUTE_GROUP,
JSON_PATH_HEADER_KEY,
PROOF_HEADER_KEY,
SERVER_PORT,
} from "./constants";
Expand Down Expand Up @@ -48,6 +49,7 @@ export function startProxyServer(
routeMethod,
route.path,
async ({ headers, params, body, query }) => {
// Verification with the SEDA chain that the overlay node is eligible
if (!serverOptions.disableProof) {
const proofHeader = Maybe.of(headers[PROOF_HEADER_KEY]);

Expand All @@ -70,65 +72,68 @@ export function startProxyServer(

// Add the request search params (?one=two) to the upstream url
const requestSearchParams = createUrlSearchParams(query);
let proxyUrl = replaceParams(route.upstreamUrl, params);
proxyUrl = injectSearchParamsInUrl(
proxyUrl,
let upstreamUrl = replaceParams(route.upstreamUrl, params);
upstreamUrl = injectSearchParamsInUrl(
upstreamUrl,
requestSearchParams,
).toString();

const proxyHeaders = new Headers();
const upstreamHeaders = new Headers();

// Redirect all headers given by the requester
for (const [key, value] of Object.entries(headers)) {
if (!value) {
continue;
}

proxyHeaders.append(key, value);
upstreamHeaders.append(key, value);
}

// Inject all configured headers by the data proxy node configuration
for (const [key, value] of Object.entries(route.headers)) {
proxyHeaders.append(key, replaceParams(value, params));
upstreamHeaders.append(key, replaceParams(value, params));
}

// Required to make it work...
proxyHeaders.delete("host");
upstreamHeaders.delete("host");

logger.debug(
`${routeMethod} ${proxyGroup}${route.path} -> ${proxyUrl}`,
`${routeMethod} ${proxyGroup}${route.path} -> ${upstreamUrl}`,
);

const proxyResponse = await tryAsync(async () =>
fetch(proxyUrl, {
const upstreamResponse = await tryAsync(async () =>
fetch(upstreamUrl, {
method: routeMethod,
headers: proxyHeaders,
headers: upstreamHeaders,
body: body as BodyInit,
}),
);

if (proxyResponse.isErr) {
if (upstreamResponse.isErr) {
return createErrorResponse(
`Proxying URL ${route.path} failed: ${proxyResponse.error}`,
`Proxying URL ${route.path} failed: ${upstreamResponse.error}`,
500,
);
}

const textResponse = await tryAsync(
async () => await proxyResponse.value.text(),
const upstreamTextResponse = await tryAsync(
async () => await upstreamResponse.value.text(),
);

if (textResponse.isErr) {
if (upstreamTextResponse.isErr) {
return createErrorResponse(
`Parsing ${route.path} response to JSON failed: ${textResponse.error}`,
`Parsing ${route.path} response to JSON failed: ${upstreamTextResponse.error}`,
500,
);
}

let responseData: string = textResponse.value;
let responseData: string = upstreamTextResponse.value;

if (route.jsonPath) {
const data = queryJson(textResponse.value, route.jsonPath);
const data = queryJson(
upstreamTextResponse.value,
route.jsonPath,
);

if (data.isErr) {
return createErrorResponse(data.error, 500);
Expand All @@ -137,13 +142,28 @@ export function startProxyServer(
responseData = JSON.stringify(data.value);
}

const jsonPathRequestHeader = Maybe.of(
headers[JSON_PATH_HEADER_KEY],
);

if (jsonPathRequestHeader.isJust) {
// We query on the responseData since the proxy node can configure to not show all data
const data = queryJson(responseData, jsonPathRequestHeader.value);

if (data.isErr) {
return createErrorResponse(data.error, 400);
}

responseData = JSON.stringify(data.value);
}

const signature = dataProxy.signData(responseData);
const responseHeaders = new Headers();

// Forward all headers that are configured in the config.json
for (const forwardHeaderKey of route.forwardRepsonseHeaders) {
const forwardHeaderValue =
proxyResponse.value.headers.get(forwardHeaderKey);
upstreamResponse.value.headers.get(forwardHeaderKey);

if (forwardHeaderValue) {
responseHeaders.append(forwardHeaderKey, forwardHeaderValue);
Expand Down
10 changes: 7 additions & 3 deletions workspace/data-proxy/src/utils/query-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ export function queryJson(
return Result.err(`Parsing as JSON failed: ${jsonData.error}`);
}

const data = JSONPath.query(jsonData.value, path);
const data = trySync(() => JSONPath.query(jsonData.value, path));

if (!data.length) {
if (data.isErr) {
return Result.err(`Could not query JSON: ${data.error}`);
}

if (!data.value.length) {
return Result.err(`Quering JSON with ${path} returned null`);
}

return Result.ok(data[0]);
return Result.ok(data.value[0]);
}

0 comments on commit 1a35994

Please sign in to comment.