3010: Apollo 4 major update and complete security overhaul to prepare for public api support
* 2919: rewrite for update to apollo 4 (#131) * rewrite for update to apollo 4 * removed container tests, edited make to publish any branch to staging * revert makefile * cleanup * update 1 * more fixes to get it working on aws * enabled csrf prevention protection, testing if build works * switched to express version * changed the healthcheck url * added cache to restdatasources * 3011: create a login mutation on graphql server that responds with a access token (#133) * 3011 added login rest endpoint and general scope fixes * changed login auth to basic auth username and password * minor changes from CR feedback * force update * added tighter timeout for idle knex connection * Refactor authentication and scopes (#134) * big refactor of scopes in graphql * cr fixes * some security fixes (#135) * some security fixes * cleanup * update staging * minor readme change
This commit is contained in:
+55
-92
@@ -1,116 +1,79 @@
|
||||
const newrelic = require('newrelic');
|
||||
const newRelicPlugin = require('@newrelic/apollo-server-plugin');
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
import { ApolloServer, AuthenticationError } from 'apollo-server';
|
||||
import knexStringcase from 'knex-stringcase';
|
||||
import { dbConfig } from './config';
|
||||
|
||||
import { ApolloServer } from '@apollo/server';
|
||||
import { expressMiddleware } from '@apollo/server/express4';
|
||||
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
|
||||
import resolvers from './resolvers';
|
||||
import { OrderAPI } from './datasources/order-api';
|
||||
import { ProductAPI } from './datasources/product-api';
|
||||
import { DesignerAPI } from './datasources/designer-api';
|
||||
import { CategoryAPI } from './datasources/category-api';
|
||||
import { KeywordAPI } from './datasources/keyword-api';
|
||||
import { MarketLocaleAPI } from './datasources/market-locale-api';
|
||||
import { ImageServerApi } from './datasources/imageserver-api';
|
||||
import { InteriorAPI } from './datasources/interior-api';
|
||||
|
||||
import { verifyToken } from './cognito/cognito-client';
|
||||
import { readFileSync } from 'fs';
|
||||
import { InteriorsLambdaAPI } from './datasources/interiors-lambda-api';
|
||||
import { TextsAPI } from './datasources/texts-api';
|
||||
import { PrintProductDefaultsAPI } from './datasources/printproduct-defaults-api';
|
||||
const newRelicPlugin = require('@newrelic/apollo-server-plugin');
|
||||
import { ContextValue } from './context';
|
||||
import { GraphQLFormattedError } from 'graphql';
|
||||
import express from 'express';
|
||||
import http from 'http';
|
||||
import cors from 'cors';
|
||||
import { json } from 'body-parser';
|
||||
import { getClientAccessToken } from './rest/cognitoService';
|
||||
|
||||
const path = require('path');
|
||||
const typeDefs = readFileSync(
|
||||
path.join(__dirname, './schema.graphql'),
|
||||
).toString('utf-8');
|
||||
|
||||
// Converts column names to CamelCase
|
||||
const knexConfig = knexStringcase(dbConfig);
|
||||
|
||||
// set up any dataSources our resolvers need
|
||||
const marketLocaleApi = new MarketLocaleAPI(knexConfig);
|
||||
const textsApi = new TextsAPI(knexConfig, marketLocaleApi);
|
||||
const categoryApi = new CategoryAPI(knexConfig);
|
||||
const designerApi = new DesignerAPI(knexConfig);
|
||||
const imageServerApi = new ImageServerApi();
|
||||
const interiorsLambdaApi = new InteriorsLambdaAPI();
|
||||
const interiorApi = new InteriorAPI(knexConfig, imageServerApi);
|
||||
const printProductDefaultsApi = new PrintProductDefaultsAPI(knexConfig);
|
||||
const keywordApi = new KeywordAPI(knexConfig, textsApi);
|
||||
const orderApi = new OrderAPI(knexConfig);
|
||||
const productApi = new ProductAPI(
|
||||
knexConfig,
|
||||
textsApi,
|
||||
printProductDefaultsApi,
|
||||
);
|
||||
|
||||
const dataSources = () => ({
|
||||
categoryApi,
|
||||
designerApi,
|
||||
interiorApi,
|
||||
printProductDefaultsApi,
|
||||
interiorsLambdaApi,
|
||||
imageServerApi,
|
||||
keywordApi,
|
||||
marketLocaleApi,
|
||||
orderApi,
|
||||
productApi,
|
||||
});
|
||||
|
||||
const context = async ({ req }) => {
|
||||
if (process.env.NODE_ENV == 'test') {
|
||||
return { auth: { userName: 'testuser' } };
|
||||
}
|
||||
|
||||
const authHeader = req.headers.authorization || '';
|
||||
if (authHeader.startsWith('Bearer ')) {
|
||||
const token = authHeader.substring(7, authHeader.length);
|
||||
const res = await verifyToken({ token });
|
||||
if (res.isValid) {
|
||||
return { auth: res };
|
||||
}
|
||||
} else if (
|
||||
process.env.NODE_ENV === 'development' &&
|
||||
authHeader == 'Basic ZGV2OnB2N1VmYSFiZVAzeGk='
|
||||
) {
|
||||
return {
|
||||
auth: {
|
||||
userName: 'testuser',
|
||||
isValid: true,
|
||||
accessToken: null,
|
||||
idToken: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
throw new AuthenticationError('Not authorized');
|
||||
};
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const server = new ApolloServer({
|
||||
const app = express();
|
||||
const httpServer = http.createServer(app);
|
||||
const server = new ApolloServer<ContextValue>({
|
||||
typeDefs,
|
||||
resolvers,
|
||||
dataSources,
|
||||
context,
|
||||
introspection: true,
|
||||
plugins: [newRelicPlugin],
|
||||
formatError: (err) => {
|
||||
console.log('Error (fmt):', err);
|
||||
newrelic.noticeError(err);
|
||||
return err;
|
||||
plugins: [
|
||||
newRelicPlugin,
|
||||
ApolloServerPluginDrainHttpServer({ httpServer }),
|
||||
],
|
||||
formatError: (formattedError: GraphQLFormattedError, error: unknown) => {
|
||||
console.error(error);
|
||||
newrelic.noticeError(error);
|
||||
return formattedError;
|
||||
},
|
||||
});
|
||||
|
||||
await server.listen();
|
||||
await server.start();
|
||||
|
||||
console.log(
|
||||
'Server is running on http://localhost:4000, ',
|
||||
process.env.ENVIRONMENT_NAME,
|
||||
app.get('/health', (req, res) => {
|
||||
res.status(200).send('OK');
|
||||
});
|
||||
|
||||
app.post('/login', async (req, res) => {
|
||||
try {
|
||||
const response = await getClientAccessToken(req);
|
||||
res.status(200).send(response);
|
||||
} catch (e) {
|
||||
newrelic.noticeError(e.message);
|
||||
res.status(401).send(e.message);
|
||||
}
|
||||
});
|
||||
|
||||
app.use(
|
||||
'/',
|
||||
cors<cors.CorsRequest>(),
|
||||
json(),
|
||||
expressMiddleware(server, {
|
||||
context: async ({ req }) => {
|
||||
const instance = new ContextValue({ req, server });
|
||||
const context = await instance.process();
|
||||
return context;
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await new Promise<void>((resolve) =>
|
||||
httpServer.listen({ port: 4000 }, resolve),
|
||||
);
|
||||
|
||||
console.log('SERVER IS RUNNING');
|
||||
console.log(`ENV: ${process.env.ENVIRONMENT_NAME}`);
|
||||
} catch (ex) {
|
||||
newrelic.noticeError(ex);
|
||||
console.error('Got terminal exception:', ex);
|
||||
|
||||
Reference in New Issue
Block a user