UNPKG

@graphql-hive/plugin-aws-sigv4

Version:
320 lines (314 loc) • 11.8 kB
import { UnifiedGraphPlugin, Instrumentation as Instrumentation$2 } from '@graphql-mesh/fusion-runtime'; import { Plugin, YogaInitialContext, Instrumentation as Instrumentation$1 } from 'graphql-yoga'; import { MeshFetch, Logger, MeshPubSub, KeyValueCache, OnFetchHook } from '@graphql-mesh/types'; import { FetchInstrumentation } from '@graphql-mesh/utils'; import { MaybePromise } from '@graphql-tools/utils'; import { MaybePromise as MaybePromise$1 } from '@whatwg-node/promise-helpers'; import { ServerAdapterInitialContext } from '@whatwg-node/server'; interface GatewayConfigContext { /** * WHATWG compatible Fetch implementation. */ fetch: MeshFetch; /** * The logger to use throught Mesh and it's plugins. */ logger: Logger; /** * Current working directory. */ cwd: string; /** * Event bus for pub/sub. */ pubsub?: MeshPubSub; /** * Cache Storage */ cache?: KeyValueCache; } interface GatewayContext extends GatewayConfigContext, YogaInitialContext { /** * Environment agnostic HTTP headers provided with the request. */ headers: Record<string, string>; /** * Runtime context available within WebSocket connections. */ connectionParams: Record<string, string>; } type GatewayPlugin<TPluginContext extends Record<string, any> = Record<string, any>, TContext extends Record<string, any> = Record<string, any>> = Plugin<Partial<TPluginContext> & GatewayContext & TContext> & UnifiedGraphPlugin<Partial<TPluginContext> & GatewayContext & TContext> & { onFetch?: OnFetchHook<Partial<TPluginContext> & GatewayContext & TContext>; onCacheGet?: OnCacheGetHook; onCacheSet?: OnCacheSetHook; onCacheDelete?: OnCacheDeleteHook; /** * An Instrumentation instance that will wrap each phases of the request pipeline. * This should be used primarily as an observability tool (for monitoring, tracing, etc...). * * Note: The wrapped functions in instrumentation should always be called. Use hooks to * conditionally skip a phase. */ instrumentation?: Instrumentation<TPluginContext & TContext & GatewayContext>; }; type OnCacheGetHook = (payload: OnCacheGetHookEventPayload) => MaybePromise<OnCacheGetHookResult | void>; interface OnCacheGetHookEventPayload { cache: KeyValueCache; key: string; ttl?: number; } interface OnCacheGetHookResult { onCacheHit?: OnCacheHitHook; onCacheMiss?: OnCacheMissHook; onCacheGetError?: OnCacheErrorHook; } type OnCacheErrorHook = (payload: OnCacheErrorHookPayload) => void; interface OnCacheErrorHookPayload { error: Error; } type OnCacheHitHook = (payload: OnCacheHitHookEventPayload) => void; interface OnCacheHitHookEventPayload { value: any; } type OnCacheMissHook = () => void; type OnCacheSetHook = (payload: OnCacheSetHookEventPayload) => MaybePromise<OnCacheSetHookResult | void>; interface OnCacheSetHookResult { onCacheSetDone?: () => void; onCacheSetError?: OnCacheErrorHook; } interface OnCacheSetHookEventPayload { cache: KeyValueCache; key: string; value: any; ttl?: number; } type OnCacheDeleteHook = (payload: OnCacheDeleteHookEventPayload) => MaybePromise<OnCacheDeleteHookResult | void>; interface OnCacheDeleteHookResult { onCacheDeleteDone?: () => void; onCacheDeleteError?: OnCacheErrorHook; } interface OnCacheDeleteHookEventPayload { cache: KeyValueCache; key: string; } type Instrumentation<TContext extends Record<string, any>> = Instrumentation$1<TContext> & Instrumentation$2 & FetchInstrumentation; declare global { var DEBUG: string; } interface AWSSignv4PluginOptions { /** * Outgoing options for signing outgoing requests. */ outgoing?: AWSSignv4PluginOutgoingOptions | AWSSignv4PluginOutgoingOptionsFactory; /** * Incoming options for validating incoming requests. */ incoming?: AWSSignv4PluginIncomingOptions | boolean; } interface AWSSignv4PluginOutgoingOptions { /** * To sign the query instead of adding an Authorization header * @default false */ signQuery?: boolean; /** * Service name to use when signing the request. * By default, it is inferred from the hostname. */ serviceName?: string; /** * Region name to use when signing the request. * By default, it is inferred from the hostname. */ region?: string; /** * ACCESS_KEY_ID * @default process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY */ accessKeyId?: string; /** * AWS_SECRET_ACCESS_KEY * @default process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY */ secretAccessKey?: string; /** * AWS_SESSION_TOKEN * @default process.env.AWS_SESSION_TOKEN */ sessionToken?: string; /** * An identifier for the assumed role session. * * @default process.env.AWS_ROLE_ARN */ roleArn?: string; /** * The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as * managed session policies. The policies must exist in the same account as the role. * * @default process.env.AWS_IAM_ROLE_SESSION_NAME */ roleSessionName?: string; } interface AWSSignv4PluginOutgoingOptionsFactoryOptions { url: string; options: RequestInit; subgraphName: string; } type AWSSignv4PluginOutgoingOptionsFactory = (factoryOptions: AWSSignv4PluginOutgoingOptionsFactoryOptions) => AWSSignv4PluginOutgoingOptions | undefined | false | true; interface AWSSignv4PluginIncomingPayload { /** * HTTP request */ request: Request; /** * Context */ serverContext: ServerAdapterInitialContext; /** * Incoming authorization headers string. Required. */ authorization: string; /** * DateTime from incoming header. Required. */ xAmzDate: string; /** * Additional header to set message exiration time even if signature message is valid. Optional. */ xAmzExpires?: number; /** * Sha256 + formated hex for body. Empty body has own bodyHash. If there is no need to sign body for performance reason you can put UNSIGNED-PAYLOAD in request headers['x-amz-content-sha256']. */ bodyHash: string; /** * accessKey used to sign this message. */ accessKey: string; /** * Date used in authorization header. */ date: string; /** * Region used in authorization header. Here can be any value. */ region: string; /** * Service used in authorization header. Here can be any value. */ service: string; /** * For aws4 will be aws4_request. Here can be any value. */ requestType: string; /** * List of signed headers separated with semicolon. */ signedHeaders: string; /** * Formated encoded header paris. */ canonicalHeaders: string; secretAccessKey?: string; } interface AssumeRolePayload { /** * Region name to use when signing the request. * By default, it is inferred from the hostname. */ region?: string; /** * An identifier for the assumed role session. * * @default process.env.AWS_ROLE_ARN */ roleArn?: string; /** * The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as * managed session policies. The policies must exist in the same account as the role. * * @default process.env.AWS_IAM_ROLE_SESSION_NAME */ roleSessionName?: string; } interface AWSSignv4PluginIncomingOptions { /** * Callback for secretKey. You have to provide process to get proper secret or return undefined secret. * By default it uses `accessKey` to get secret from `process.env.AWS_SECRET_ACCESS_KEY` or `process.env.AWS_SECRET_KEY`. * Should return secretKey on incoming parameters - but if secret is missing which it will be normal case when someone want to guess - you should return undefined; */ secretAccessKey?: (payload: AWSSignv4PluginIncomingPayload) => MaybePromise$1<string | undefined> | string | undefined; /** * An identifier for the assumed role session. * * @default process.env.AWS_ROLE_ARN */ assumeRole?: (payload: AWSSignv4PluginIncomingPayload) => MaybePromise$1<AssumeRolePayload | undefined> | AssumeRolePayload | undefined; /** * Callback for changes in incoming headers before it goes through parse process. Help to more sophisticated changes to preserve proper headers. */ headers?: (headers: Headers) => Headers; /** * You can skip aws signature validation. It is useful when you want to use it only for some requests. */ enabled?: (request: Request, serverContext: ServerAdapterInitialContext) => MaybePromise$1<boolean>; /** * Callback on header missing. Validation stops here. Default value `onMissingHeaders: () => { throw new GraphQLError('Headers are missing for auth', { extensions: { http: { status: 401, } } }); },` */ onMissingHeaders?: (request: Request, serverContext: ServerAdapterInitialContext) => MaybePromise$1<void>; /** * Custom response on signature mismatch. Validation stops here. Default value `onSignatureMismatch: () => { throw new GraphQLError('The signature does not match', { extensions: { http: { status: 401, } } }); },` */ onSignatureMismatch?: (request: Request, serverContext: ServerAdapterInitialContext) => MaybePromise$1<void>; /** * Custom response on exired time signature. Validation stops here. Default value `onExpired: () => { throw new GraphQLError('Request is expired', { extensions: { http: { status: 401, } } }); },` */ onExpired?: (request: Request, serverContext: ServerAdapterInitialContext) => MaybePromise$1<void>; /** * Custom callback before standard parser comes. On false validation stops here. Default value `onBeforeParse: () => true,` * * Should return true if you need to let parse request further. */ onBeforeParse?: (request: Request, serverContext: ServerAdapterInitialContext) => MaybePromise$1<boolean>; /** * Custom callback after standard parser done. On false validation stops here. Default value `onAfterParse: () => true,` * Should return true if you need to let parse request further. */ onAfterParse?: (payload: AWSSignv4PluginIncomingPayload) => MaybePromise$1<boolean>; /** * Last callback after when validation signature is done. You can even stop here process. */ onSuccess?: (payload: AWSSignv4PluginIncomingPayload) => MaybePromise$1<void>; } declare enum AWSSignV4Headers { 'Authorization' = "authorization", 'XAmzDate' = "x-amz-date", 'XAmzContentSha256' = "x-amz-content-sha256", 'XAmzExpires' = "x-amz-expires" } declare function useAWSSigv4<TContext extends Record<string, any>>(opts: AWSSignv4PluginOptions): GatewayPlugin<TContext>; export { AWSSignV4Headers, type AWSSignv4PluginIncomingOptions, type AWSSignv4PluginIncomingPayload, type AWSSignv4PluginOptions, type AWSSignv4PluginOutgoingOptions, type AWSSignv4PluginOutgoingOptionsFactory, type AWSSignv4PluginOutgoingOptionsFactoryOptions, type AssumeRolePayload, useAWSSigv4 };