Skip to content

Commit

Permalink
Merge pull request #9 from JoinColony/add-wallet-header
Browse files Browse the repository at this point in the history
Forward user's address to lambdas in a header
  • Loading branch information
jakubcolony authored Feb 6, 2024
2 parents 80bdcb9 + 44f167e commit f4b74a3
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 38 deletions.
116 changes: 84 additions & 32 deletions src/routes/graphql/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import dotenv from "dotenv";
import { fixRequestBody, Options, RequestHandler } from "http-proxy-middleware";
import dotenv from 'dotenv';
import { fixRequestBody, Options, RequestHandler } from 'http-proxy-middleware';
import { Response, Request, NextFunction } from 'express-serve-static-core';
import { ClientRequest, IncomingMessage } from 'http';

Expand Down Expand Up @@ -27,10 +27,13 @@ dotenv.config();
export const operationExecutionHandler: RequestHandler = async (
request: Request,
response: Response,
nextFn: NextFunction
nextFn: NextFunction,
) => {
// short circut early
if (request.path !== Urls.GraphQL || request.method !== ServerMethods.Post.toUpperCase()) {
if (
request.path !== Urls.GraphQL ||
request.method !== ServerMethods.Post.toUpperCase()
) {
return nextFn();
}

Expand All @@ -41,7 +44,13 @@ export const operationExecutionHandler: RequestHandler = async (
response.locals.canExecute = await addressCanExecuteMutation(request);
return nextFn();
} catch (error: any) {
logger(`${userAddress ? `auth-${userAddress}` : 'non-auth'} request malformed graphql ${request.body ? JSON.stringify(request.body) : ''} from ${requestRemoteAddress}`);
logger(
`${
userAddress ? `auth-${userAddress}` : 'non-auth'
} request malformed graphql ${
request.body ? JSON.stringify(request.body) : ''
} from ${requestRemoteAddress}`,
);
return sendResponse(response, request, error, HttpStatuses.SERVER_ERROR);
}
};
Expand All @@ -67,59 +76,102 @@ export const graphQlProxyRouteHandler: Options = {
/*
* Used for UI only, the real magic with detection happens in operationExecutionHandler
*/
const { operationType, operations, variables } = detectOperation(request.body);
const { operationType, operations, variables } = detectOperation(
request.body,
);

/*
* Queries are all allowed, while mutations need to be handled on a case by case basis
* Some are allowed without auth (cache refresh ones)
* Others based on if the user has the appropriate address and/or role
*/
const canExecute = response.locals.canExecute || operationType === OperationTypes.Query;
const canExecute =
response.locals.canExecute || operationType === OperationTypes.Query;

logger(`${userAuthenticated ? `auth` : 'non-auth'} ${operationType} ${operations} ${JSON.stringify(variables).slice(0, 500)}${JSON.stringify(variables).length > 499 ? ` [+${JSON.stringify(variables).length - 499} chars more]` : ''}${userAddress ? ` from ${userAddress}` : ''} at ${requestRemoteAddress} was ${canExecute ? 'ALLOWED' : 'FORBIDDEN'}`);
logger(
`${
userAuthenticated ? `auth` : 'non-auth'
} ${operationType} ${operations} ${JSON.stringify(variables).slice(
0,
500,
)}${
JSON.stringify(variables).length > 499
? ` [+${JSON.stringify(variables).length - 499} chars more]`
: ''
}${
userAddress ? ` from ${userAddress}` : ''
} at ${requestRemoteAddress} was ${
canExecute ? 'ALLOWED' : 'FORBIDDEN'
}`,
);

// allowed
if (canExecute) {
proxyRequest.setHeader(Headers.WalletAddress, userAddress);
return fixRequestBody(proxyRequest, request);
}

// forbidden
return sendResponse(response, request, {
message: 'forbidden',
type: ResponseTypes.Auth,
data: '',
}, HttpStatuses.FORBIDDEN);
return sendResponse(
response,
request,
{
message: 'forbidden',
type: ResponseTypes.Auth,
data: '',
},
HttpStatuses.FORBIDDEN,
);
}

/*
* Malformed request
*/
logger(`${userAuthenticated ? `auth` : 'non-auth'} request malformed graphql ${request.body ? JSON.stringify(request.body) : ''}${userAddress ? ` from ${userAddress}` : ''} at ${requestRemoteAddress}`);
return sendResponse(response, request, {
message: 'malformed graphql request',
type: ResponseTypes.Error,
data: '',
}, HttpStatuses.SERVER_ERROR);

logger(
`${userAuthenticated ? `auth` : 'non-auth'} request malformed graphql ${
request.body ? JSON.stringify(request.body) : ''
}${
userAddress ? ` from ${userAddress}` : ''
} at ${requestRemoteAddress}`,
);
return sendResponse(
response,
request,
{
message: 'malformed graphql request',
type: ResponseTypes.Error,
data: '',
},
HttpStatuses.SERVER_ERROR,
);
} catch (error: any) {

/*
* GraphQL error (comes from the AppSync endopoint)
*/
logger(`${userAuthenticated ? `auth` : 'non-auth'} graphql proxy error ${error?.message} ${request.body ? JSON.stringify(request.body) : ''}${userAddress ? ` from ${userAddress}` : ''} at ${requestRemoteAddress}`);
return sendResponse(response, request, {
message: 'graphql error',
type: ResponseTypes.Error,
data: error?.message || '',
}, HttpStatuses.SERVER_ERROR);
logger(
`${userAuthenticated ? `auth` : 'non-auth'} graphql proxy error ${
error?.message
} ${request.body ? JSON.stringify(request.body) : ''}${
userAddress ? ` from ${userAddress}` : ''
} at ${requestRemoteAddress}`,
);
return sendResponse(
response,
request,
{
message: 'graphql error',
type: ResponseTypes.Error,
data: error?.message || '',
},
HttpStatuses.SERVER_ERROR,
);
}
},
// selfHandleResponse: true,
onProxyRes: (
proxyResponse: IncomingMessage,
request: Request,
) => {
proxyResponse.headers[Headers.AllowOrigin] = getStaticOrigin(request.headers.origin);
onProxyRes: (proxyResponse: IncomingMessage, request: Request) => {
proxyResponse.headers[Headers.AllowOrigin] = getStaticOrigin(
request.headers.origin,
);
proxyResponse.headers[Headers.PoweredBy] = 'Colony';
},
logProvider: () => ({
Expand Down
20 changes: 14 additions & 6 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export enum DefinitionTypes {

export enum MutationOperations {
/*
* User
*/
* User
*/
CreateUniqueUser = 'createUniqueUser',
UpdateUserProfile = 'updateProfile',
CreateTransaction = 'createTransaction',
Expand Down Expand Up @@ -55,7 +55,7 @@ export enum HttpStatuses {
FORBIDDEN = 403,
SERVER_ERROR = 500,
UNPROCESSABLE = 422,
};
}

export enum ResponseTypes {
Nonce = 'nonce',
Expand All @@ -69,7 +69,7 @@ export type Response = {
message: string;
type: ResponseTypes;
data?: string | number | boolean | string[] | number[] | boolean[];
}
};

export enum Urls {
GraphQL = '/graphql',
Expand All @@ -94,10 +94,18 @@ export enum Headers {
ForwardedProto = 'x-forwarded-proto',
ApiKey = 'x-api-key',
PoweredBy = 'X-Powered-By',
WalletAddress = 'x-wallet-address',
}

export type StaticOrigin = boolean | string | RegExp | (boolean | string | RegExp)[];
export type StaticOriginCallback = (err: Error | null, origin?: StaticOrigin | undefined) => void;
export type StaticOrigin =
| boolean
| string
| RegExp
| (boolean | string | RegExp)[];
export type StaticOriginCallback = (
err: Error | null,
origin?: StaticOrigin | undefined,
) => void;

export enum ServerMethods {
Post = 'post',
Expand Down

0 comments on commit f4b74a3

Please sign in to comment.