Skip to content

Commit

Permalink
fix(server): rename whitelist to allow-list
Browse files Browse the repository at this point in the history
maintaining compat until next major release
  • Loading branch information
rhyslbw committed Aug 3, 2020
1 parent 58a1e6a commit eeeafa9
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 37 deletions.
6 changes: 3 additions & 3 deletions nix/nixos/cardano-graphql-service.nix
Expand Up @@ -82,10 +82,10 @@ in {
default = false;
description = "Allows introspection queries";
};
whitelistPath = lib.mkOption {
allowListPath = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = "Source directory or file to generate whitelist from";
description = "Source directory or file to generate allow-list from";
};
};
};
Expand Down Expand Up @@ -126,7 +126,7 @@ in {
} //
(lib.optionalAttrs (cfg.allowedOrigins != null) { ALLOWED_ORIGINS = cfg.allowedOrigins; }) //
(lib.optionalAttrs (cfg.queryDepthLimit != null) { QUERY_DEPTH_LIMIT = toString cfg.queryDepthLimit; }) //
(lib.optionalAttrs (cfg.whitelistPath != null) { WHITELIST_PATH = cfg.whitelistPath; });
(lib.optionalAttrs (cfg.allowListPath != null) { ALLOW_LIST_PATH = cfg.allowListPath; });
path = with pkgs; [ netcat curl postgresql jq frontend hasura-cli glibc.bin patchelf ];
preStart = ''
set -exuo pipefail
Expand Down
@@ -1,16 +1,16 @@
import { ForbiddenError } from 'apollo-server-errors'
import { PluginDefinition } from 'apollo-server-core'

export function whitelistPlugin (whitelist: {[key: string]: number }): PluginDefinition {
export function allowListPlugin (allowList: {[key: string]: number }): PluginDefinition {
return {
serverWillStart (_service) {
console.log(`The server is configured to accept ${Object.keys(whitelist).length} operations from the provided whitelist`)
console.log(`The server is configured to accept ${Object.keys(allowList).length} operations from the provided allow-list`)
},
requestDidStart () {
return {
parsingDidStart (context) {
if (whitelist[context.request.query] === undefined) {
throw new ForbiddenError('Operation is forbidden')
if (allowList[context.request.query] === undefined) {
throw new ForbiddenError('Operation is disallowed')
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/apollo_server_plugins/index.ts
@@ -1,2 +1,2 @@
export * from './prometheus_metrics_plugin'
export * from './whitelist_plugin'
export * from './allow_list_plugin'
23 changes: 14 additions & 9 deletions packages/server/src/config.ts
Expand Up @@ -4,6 +4,7 @@ import { IntrospectionNotPermitted, MissingConfig, TracingRequired } from './err
export type Config = {
allowIntrospection?: boolean
allowedOrigins: CorsOptions['origin']
allowListPath: string
apiPort: number
cacheEnabled: boolean
genesisFileByron: string
Expand All @@ -13,13 +14,13 @@ export type Config = {
prometheusMetrics: boolean
queryDepthLimit: number
tracing: boolean
whitelistPath: string
}

export async function getConfig (): Promise<Config> {
const {
allowIntrospection,
allowedOrigins,
allowListPath,
apiPort,
cacheEnabled,
genesisFileByron,
Expand All @@ -28,8 +29,7 @@ export async function getConfig (): Promise<Config> {
poolMetadataProxy,
prometheusMetrics,
queryDepthLimit,
tracing,
whitelistPath
tracing
} = filterAndTypecastEnvs(process.env)

if (!hasuraUri && !genesisFileShelley) {
Expand All @@ -38,12 +38,13 @@ export async function getConfig (): Promise<Config> {
if (prometheusMetrics && process.env.TRACING === 'false') {
throw new TracingRequired('Prometheus')
}
if (whitelistPath && allowIntrospection) {
throw new IntrospectionNotPermitted('whitelist')
if (allowListPath && allowIntrospection) {
throw new IntrospectionNotPermitted('allowList')
}
return {
allowIntrospection,
allowedOrigins: allowedOrigins || true,
allowListPath,
apiPort: apiPort || 3100,
cacheEnabled: cacheEnabled || false,
genesisFileByron,
Expand All @@ -52,15 +53,15 @@ export async function getConfig (): Promise<Config> {
poolMetadataProxy,
prometheusMetrics,
queryDepthLimit: queryDepthLimit || 10,
tracing,
whitelistPath
tracing
}
}

function filterAndTypecastEnvs (env: any) {
const {
ALLOW_INTROSPECTION,
ALLOWED_ORIGINS,
ALLOW_LIST_PATH,
API_PORT,
CACHE_ENABLED,
GENESIS_FILE_BYRON,
Expand All @@ -72,9 +73,14 @@ function filterAndTypecastEnvs (env: any) {
TRACING,
WHITELIST_PATH
} = env
if (WHITELIST_PATH) {
console.log(`WHITELIST_PATH is deprecated and will be removed in 3.0.0.
Please update your configuration to use ALLOW_LIST_PATH instead.`)
}
return {
allowIntrospection: ALLOW_INTROSPECTION === 'true' ? true : undefined,
allowedOrigins: ALLOWED_ORIGINS,
allowListPath: ALLOW_LIST_PATH || WHITELIST_PATH,
apiPort: Number(API_PORT),
cacheEnabled: CACHE_ENABLED === 'true' ? true : undefined,
genesisFileByron: GENESIS_FILE_BYRON,
Expand All @@ -83,7 +89,6 @@ function filterAndTypecastEnvs (env: any) {
poolMetadataProxy: POOL_METADATA_PROXY,
prometheusMetrics: PROMETHEUS_METRICS === 'true' ? true : undefined,
queryDepthLimit: Number(QUERY_DEPTH_LIMIT),
tracing: TRACING === 'true' ? true : undefined,
whitelistPath: WHITELIST_PATH
tracing: TRACING === 'true' ? true : undefined
}
}
12 changes: 6 additions & 6 deletions packages/server/src/index.ts
Expand Up @@ -12,7 +12,7 @@ import { GraphQLSchema } from 'graphql'
export * from './config'
export { apolloServerPlugins }

const { prometheusMetricsPlugin, whitelistPlugin } = apolloServerPlugins
const { prometheusMetricsPlugin, allowListPlugin } = apolloServerPlugins

async function boot () {
const config = await getConfig()
Expand All @@ -37,9 +37,9 @@ async function boot () {
if (config.prometheusMetrics) {
plugins.push(prometheusMetricsPlugin(app))
}
if (config.whitelistPath) {
const whitelist = JSON.parse(fs.readFileSync(config.whitelistPath, 'utf8'))
plugins.push(whitelistPlugin(whitelist))
if (config.allowListPath) {
const allowList = JSON.parse(fs.readFileSync(config.allowListPath, 'utf8'))
plugins.push(allowListPlugin(allowList))
}
if (config.queryDepthLimit) {
validationRules.push(depthLimit(config.queryDepthLimit))
Expand All @@ -61,8 +61,8 @@ async function boot () {
app.listen({ port: config.apiPort }, () => {
const serverUri = `http://localhost:${config.apiPort}`
console.log(`GraphQL HTTP server at ${serverUri}${server.graphqlPath}`)
if (process.env.NODE_ENV !== 'production' && config.whitelistPath) {
console.warn('As a whitelist is in effect, the GraphQL Playground is available, but will not allow schema exploration')
if (process.env.NODE_ENV !== 'production' && config.allowListPath) {
console.warn('As an allow-list is in effect, the GraphQL Playground is available, but will not allow schema exploration')
}
if (config.prometheusMetrics) {
console.log(`Prometheus metrics at ${serverUri}/metrics`)
Expand Down
26 changes: 13 additions & 13 deletions packages/server/test/Server.test.ts
Expand Up @@ -11,7 +11,7 @@ import tmp from 'tmp-promise'
import util from '@cardano-graphql/util'
import { buildSchema as buildGenesisSchema } from '@cardano-graphql/api-genesis'
import { Server } from '@src/Server'
import { whitelistPlugin } from '@src/apollo_server_plugins'
import { allowListPlugin } from '@src/apollo_server_plugins'

const byronTestnetGenesis = '../../../config/network/testnet/genesis/byron.json'
const shelleyTestnetGenesis = '../../../config/network/testnet/genesis/shelley.json'
Expand All @@ -27,14 +27,14 @@ function listen (app: Application, port: number): Promise<http.Server> {

describe('Server', () => {
let client: ApolloClient<any>
let whiteListedDocumentNode: DocumentNode
let allowedDocumentNode: DocumentNode
let app: express.Application
let httpServer: http.Server
let genesisSchema: GraphQLSchema

beforeAll(async () => {
genesisSchema = buildGenesisSchema({ byron: require(byronTestnetGenesis), shelley: require(shelleyTestnetGenesis) })
whiteListedDocumentNode = await util.loadQueryNode(path.resolve(clientPath, 'src', 'feature_1'), 'maxLovelaceSupply')
allowedDocumentNode = await util.loadQueryNode(path.resolve(clientPath, 'src', 'feature_1'), 'maxLovelaceSupply')
})

beforeEach(async () => {
Expand All @@ -58,8 +58,8 @@ describe('Server', () => {
app = express()
})

describe('Whitelisting', () => {
describe('Booting the server without providing a whitelist', () => {
describe('Allowing specific queries', () => {
describe('Booting the server without providing an allow-list', () => {
beforeEach(async () => {
Server(app, {
schema: genesisSchema
Expand All @@ -85,13 +85,13 @@ describe('Server', () => {
})
})

describe('Providing a whitelist produced by persistgraphql, intended to limit the API for specific application requirements', () => {
describe('Providing an allow-list produced by persistgraphql, intended to limit the API for specific application requirements', () => {
beforeEach(async () => {
const whitelistPath = await tmp.tmpName({ postfix: '.json' })
execSync(`npx persistgraphql ${clientPath} ${whitelistPath}`)
const whitelist = JSON.parse(fs.readFileSync(whitelistPath, 'utf-8'))
const allowlistPath = await tmp.tmpName({ postfix: '.json' })
execSync(`npx persistgraphql ${clientPath} ${allowlistPath}`)
const allowList = JSON.parse(fs.readFileSync(allowlistPath, 'utf-8'))
Server(app, {
plugins: [whitelistPlugin(whitelist)],
plugins: [allowListPlugin(allowList)],
schema: genesisSchema
})
httpServer = await listen(app, port)
Expand All @@ -100,14 +100,14 @@ describe('Server', () => {
httpServer.close()
})

it('Accepts listed queries', async () => {
it('Accepts allowed queries', async () => {
const result = await client.query({
query: whiteListedDocumentNode
query: allowedDocumentNode
})
expect(result.data.genesis.shelley.maxLovelaceSupply).toBeDefined()
expect(result.errors).not.toBeDefined()
})
it('Returns a networkError if a valid but unlisted operation is sent', async () => {
it('Returns a networkError if a valid but disallowed operation is sent', async () => {
expect.assertions(1)
try {
await client.query({
Expand Down
2 changes: 1 addition & 1 deletion shell.nix
Expand Up @@ -39,7 +39,7 @@ let
echo "NOTE: you may need to export GITHUB_TOKEN if you hit rate limits with niv"
echo "Commands:
* niv update <package> - update package
* persistgraphql <src> whitelist.json - generates a whitelist.json to limit graphql queries
* persistgraphql <src> allowList.json - generates an allowList.json to limit graphql queries
* export GOPATH="\$\(pwd\)/.go" - enable vgo2nix to use the pwd as it's source
* node2nix -l - update node packages, -l if there's a lock file
Expand Down

0 comments on commit eeeafa9

Please sign in to comment.