Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/apollo-server-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"graphql-tag": "^2.9.2",
"graphql-tools": "^4.0.0",
"graphql-upload": "^8.0.2",
"sha.js": "^2.4.11",
"subscriptions-transport-ws": "^0.9.11",
"ws": "^6.0.0"
},
Expand Down
5 changes: 3 additions & 2 deletions packages/apollo-server-core/src/requestPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
PersistedQueryNotSupportedError,
PersistedQueryNotFoundError,
} from 'apollo-server-errors';
import { createHash } from 'crypto';
import {
GraphQLRequest,
GraphQLResponse,
Expand All @@ -53,8 +52,10 @@ export {
InvalidGraphQLRequestError,
};

import createSHA from './utils/createSHA';

function computeQueryHash(query: string) {
return createHash('sha256')
return createSHA('sha256')
.update(query)
.digest('hex');
}
Expand Down
10 changes: 10 additions & 0 deletions packages/apollo-server-core/src/utils/createSHA.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import isNode from './isNode';

export default function(kind: string): import('crypto').Hash {
if (isNode) {
// Use module.require instead of just require to avoid bundling whatever
// crypto polyfills a non-Node bundler might fall back to.
return module.require('crypto').createHash(kind);
}
return require('sha.js')(kind);
}
6 changes: 6 additions & 0 deletions packages/apollo-server-core/src/utils/isNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default typeof process === 'object' &&
process &&
process.release &&
process.release.name === 'node' &&
process.versions &&
typeof process.versions.node === 'string';
10 changes: 3 additions & 7 deletions packages/apollo-server-core/src/utils/runtimeSupportsUploads.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import isNode from './isNode';

const runtimeSupportsUploads = (() => {
if (
process &&
process.release &&
process.release.name === 'node' &&
process.versions &&
typeof process.versions.node === 'string'
) {
if (isNode) {
const [nodeMajor, nodeMinor] = process.versions.node
.split('.', 2)
.map(segment => parseInt(segment, 10));
Expand Down
88 changes: 44 additions & 44 deletions packages/apollo-server-core/src/utils/schemaHash.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
import { parse } from 'graphql/language';
import { execute, ExecutionResult } from 'graphql/execution';
import { getIntrospectionQuery, IntrospectionSchema } from 'graphql/utilities';
import stableStringify from 'fast-json-stable-stringify';
import { GraphQLSchema } from 'graphql/type';
import { createHash } from 'crypto';
export function generateSchemaHash(schema: GraphQLSchema): string {
const introspectionQuery = getIntrospectionQuery();
const documentAST = parse(introspectionQuery);
const result = execute(schema, documentAST) as ExecutionResult;
// If the execution of an introspection query results in a then-able, it
// indicates that one or more of its resolvers is behaving in an asynchronous
// manner. This is not the expected behavior of a introspection query
// which does not have any asynchronous resolvers.
if (
result &&
typeof (result as PromiseLike<typeof result>).then === 'function'
) {
throw new Error(
[
'The introspection query is resolving asynchronously; execution of an introspection query is not expected to return a `Promise`.',
'',
'Wrapped type resolvers should maintain the existing execution dynamics of the resolvers they wrap (i.e. async vs sync) or introspection types should be excluded from wrapping by checking them with `graphql/type`s, `isIntrospectionType` predicate function prior to wrapping.',
].join('\n'),
);
}
if (!result || !result.data || !result.data.__schema) {
throw new Error('Unable to generate server introspection document.');
}
const introspectionSchema: IntrospectionSchema = result.data.__schema;
// It's important that we perform a deterministic stringification here
// since, depending on changes in the underlying `graphql-js` execution
// layer, varying orders of the properties in the introspection
const stringifiedSchema = stableStringify(introspectionSchema);
return createHash('sha512')
.update(stringifiedSchema)
.digest('hex');
}
import { parse } from 'graphql/language';
import { execute, ExecutionResult } from 'graphql/execution';
import { getIntrospectionQuery, IntrospectionSchema } from 'graphql/utilities';
import stableStringify from 'fast-json-stable-stringify';
import { GraphQLSchema } from 'graphql/type';
import createSHA from './createSHA';

export function generateSchemaHash(schema: GraphQLSchema): string {
const introspectionQuery = getIntrospectionQuery();
const documentAST = parse(introspectionQuery);
const result = execute(schema, documentAST) as ExecutionResult;

// If the execution of an introspection query results in a then-able, it
// indicates that one or more of its resolvers is behaving in an asynchronous
// manner. This is not the expected behavior of a introspection query
// which does not have any asynchronous resolvers.
if (
result &&
typeof (result as PromiseLike<typeof result>).then === 'function'
) {
throw new Error(
[
'The introspection query is resolving asynchronously; execution of an introspection query is not expected to return a `Promise`.',
'',
'Wrapped type resolvers should maintain the existing execution dynamics of the resolvers they wrap (i.e. async vs sync) or introspection types should be excluded from wrapping by checking them with `graphql/type`s, `isIntrospectionType` predicate function prior to wrapping.',
].join('\n'),
);
}

if (!result || !result.data || !result.data.__schema) {
throw new Error('Unable to generate server introspection document.');
}

const introspectionSchema: IntrospectionSchema = result.data.__schema;

// It's important that we perform a deterministic stringification here
// since, depending on changes in the underlying `graphql-js` execution
// layer, varying orders of the properties in the introspection
const stringifiedSchema = stableStringify(introspectionSchema);

return createSHA('sha512')
.update(stringifiedSchema)
.digest('hex');
}