2022-07-06 14:03:35 +00:00
|
|
|
import crypto from "crypto";
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
import * as jose from "jose";
|
|
|
|
import type { Middleware } from "retes";
|
|
|
|
import { Response } from "retes/response";
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
import { SALEOR_DOMAIN_HEADER, SALEOR_EVENT_HEADER } from "./const";
|
|
|
|
import { jwksUrl } from "./urls";
|
2022-05-26 12:14:13 +00:00
|
|
|
|
|
|
|
export const withBaseURL: Middleware = (handler) => async (request) => {
|
|
|
|
const { host, "x-forwarded-proto": protocol = "http" } = request.headers;
|
|
|
|
|
|
|
|
request.context.baseURL = `${protocol}://${host}`;
|
|
|
|
|
|
|
|
const response = await handler(request);
|
|
|
|
return response;
|
2022-07-06 14:03:35 +00:00
|
|
|
};
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
export const withSaleorDomainPresent: Middleware =
|
|
|
|
(handler) => async (request) => {
|
|
|
|
const saleor_domain = request.headers[SALEOR_DOMAIN_HEADER];
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
if (!saleor_domain) {
|
|
|
|
return Response.BadRequest({
|
|
|
|
success: false,
|
|
|
|
message: "Missing Saleor domain header.",
|
|
|
|
});
|
|
|
|
}
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
return handler(request);
|
|
|
|
};
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
export const withSaleorEventMatch =
|
|
|
|
(expectedEvent: string): Middleware =>
|
|
|
|
(handler) =>
|
|
|
|
async (request) => {
|
|
|
|
const receivedEvent = request.headers[SALEOR_EVENT_HEADER];
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
if (receivedEvent !== expectedEvent) {
|
|
|
|
return Response.BadRequest({
|
|
|
|
success: false,
|
|
|
|
message: "Invalid Saleor Event",
|
|
|
|
});
|
|
|
|
}
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
return handler(request);
|
|
|
|
};
|
|
|
|
|
|
|
|
export const withAuthTokenRequired: Middleware =
|
|
|
|
(handler) => async (request) => {
|
|
|
|
const auth_token = request.params.auth_token;
|
|
|
|
if (!auth_token) {
|
|
|
|
return Response.BadRequest({
|
|
|
|
success: false,
|
|
|
|
message: "Missing auth token.",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return handler(request);
|
|
|
|
};
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
export const withWebhookSignatureVerified = (
|
|
|
|
secretKey: string | undefined = undefined
|
|
|
|
): Middleware => {
|
|
|
|
return (handler) => async (request) => {
|
|
|
|
if (request.rawBody === undefined) {
|
|
|
|
return Response.InternalServerError({
|
|
|
|
success: false,
|
|
|
|
message: "Request payload already parsed.",
|
|
|
|
});
|
|
|
|
}
|
2022-05-26 12:14:13 +00:00
|
|
|
|
2022-07-06 14:03:35 +00:00
|
|
|
const {
|
|
|
|
[SALEOR_DOMAIN_HEADER]: saleorDomain,
|
|
|
|
"saleor-signature": payloadSignature,
|
|
|
|
} = request.headers;
|
|
|
|
|
|
|
|
if (secretKey !== undefined) {
|
|
|
|
const calculatedSignature = crypto
|
|
|
|
.createHmac("sha256", secretKey)
|
|
|
|
.update(request.rawBody)
|
|
|
|
.digest("hex");
|
|
|
|
|
|
|
|
if (calculatedSignature !== payloadSignature) {
|
|
|
|
return Response.BadRequest({
|
|
|
|
success: false,
|
|
|
|
message: "Invalid signature.",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const [header, _, signature] = payloadSignature.split(".");
|
|
|
|
const jws = {
|
|
|
|
protected: header,
|
|
|
|
payload: request.rawBody,
|
|
|
|
signature,
|
|
|
|
};
|
|
|
|
|
2022-07-14 12:04:27 +00:00
|
|
|
const jwks = jose.createRemoteJWKSet(
|
2022-07-06 14:03:35 +00:00
|
|
|
new URL(jwksUrl(saleorDomain))
|
2022-07-14 12:04:27 +00:00
|
|
|
) as jose.FlattenedVerifyGetKey;
|
2022-07-06 14:03:35 +00:00
|
|
|
|
|
|
|
try {
|
2022-07-14 12:04:27 +00:00
|
|
|
await jose.flattenedVerify(jws, jwks);
|
2022-07-06 14:03:35 +00:00
|
|
|
} catch {
|
|
|
|
return Response.BadRequest({
|
|
|
|
success: false,
|
|
|
|
message: "Invalid signature.",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return handler(request);
|
|
|
|
};
|
|
|
|
};
|