Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move interface projection to cypher builder #2030

Merged
36 changes: 27 additions & 9 deletions packages/graphql/src/translate/create-auth-and-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,23 @@ import mapToDbProperty from "../utils/map-to-db-property";
import { AUTH_UNAUTHENTICATED_ERROR } from "../constants";

interface Allow {
varName: string;
varName: string | CypherBuilder.Node;
parentNode: Node;
chainStr?: string;
}

interface Bind {
varName: string;
varName: string | CypherBuilder.Node;
parentNode: Node;
chainStr?: string;
}

interface Where {
varName: string | CypherBuilder.Node;
node: Node;
chainStr?: string;
}

export function createAuthAndParams({
entity,
operations,
Expand All @@ -59,7 +65,7 @@ export function createAuthAndParams({
context: Context;
escapeQuotes?: boolean;
bind?: Bind;
where?: { varName: string; chainStr?: string; node: Node };
where?: Where;
}): [string, Record<string, any>] {
const authPredicate = createAuthPredicates({
entity,
Expand All @@ -78,14 +84,22 @@ export function createAuthAndParams({
return authPredicate.getCypher(env);
});

const chainStr = `${where?.varName || ""}${allow?.varName || ""}${bind?.varName || ""}`;
const chainStr = generateUniqueChainStr([where?.varName, allow?.varName, bind?.varName]);

// Params must be globally unique, variables can be just slightly different, as each auth statement is scoped
const authCypher = authPredicateExpr.build({ params: `${chainStr}auth_`, variables: `auth_` });

return [authCypher.cypher, authCypher.params];
}

function generateUniqueChainStr(varNames: Array<string | CypherBuilder.Node | undefined>): string {
return varNames
.map((v) => {
return typeof v === "string" ? v : "";
})
.join("");
}

export function createAuthPredicates({
entity,
operations,
Expand All @@ -105,7 +119,7 @@ export function createAuthPredicates({
context: Context;
escapeQuotes?: boolean;
bind?: Bind;
where?: { varName: string; chainStr?: string; node: Node };
where?: Where;
}): CypherBuilder.Predicate | undefined {
if (!entity.auth) {
return undefined;
Expand Down Expand Up @@ -162,7 +176,7 @@ function createSubPredicate({
context: Context;
escapeQuotes?: boolean;
bind?: Bind;
where?: { varName: string; chainStr?: string; node: Node };
where?: Where;
}): CypherBuilder.Predicate | undefined {
const thisPredicates: CypherBuilder.Predicate[] = [];
const authParam = new CypherBuilder.NamedParam("auth");
Expand All @@ -181,7 +195,7 @@ function createSubPredicate({
}

if (allow && authRule.allow) {
const nodeRef = new CypherBuilder.NamedNode(allow.varName);
const nodeRef = getOrCreateCypherNode(allow.varName);
const allowAndParams = createAuthPredicate({
context,
node: allow.parentNode,
Expand Down Expand Up @@ -234,7 +248,7 @@ function createSubPredicate({
});

if (where && authRule.where) {
const nodeRef = new CypherBuilder.NamedNode(where.varName);
const nodeRef = getOrCreateCypherNode(where.varName);

const wherePredicate = createAuthPredicate({
context,
Expand All @@ -249,7 +263,7 @@ function createSubPredicate({
}

if (bind && authRule.bind) {
const nodeRef = new CypherBuilder.NamedNode(bind.varName);
const nodeRef = getOrCreateCypherNode(bind.varName);

const allowPredicate = createAuthPredicate({
context,
Expand Down Expand Up @@ -493,3 +507,7 @@ function isValueInListCypher(value: CypherBuilder.Variable, list: CypherBuilder.
const listItemVar = new CypherBuilder.Variable();
return CypherBuilder.any(listItemVar, list, CypherBuilder.eq(listItemVar, value));
}
function getOrCreateCypherNode(nameOrNode: CypherBuilder.Node | string): CypherBuilder.Node {
if (typeof nameOrNode === "string") return new CypherBuilder.NamedNode(nameOrNode);
return nameOrNode;
}
Loading