Skip to content

Commit

Permalink
test(integration): add signatures to apollo client requests
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurapov committed Dec 11, 2024
1 parent 33f0643 commit db5d0e9
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 7 deletions.
7 changes: 6 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 47 additions & 3 deletions test/integration/lib/apollo-client.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,55 @@
import type { NormalizedCacheObject } from '@apollo/client'
import { ApolloClient, InMemoryCache } from '@apollo/client'
import {
ApolloClient,
ApolloLink,
createHttpLink,
InMemoryCache
} from '@apollo/client'
import { createHmac } from 'crypto'
import { print } from 'graphql/language/printer'
import { canonicalize } from 'json-canonicalize'
import { setContext } from '@apollo/client/link/context'

export function createApolloClient(
interface CreateApolloClientArgs {
graphqlUrl: string
signatureSecret: string
signatureVersion: string
}

function createAuthLink(args: CreateApolloClientArgs) {
return setContext((request, { headers }) => {
const timestamp = Math.round(new Date().getTime() / 1000)
const version = args.signatureVersion

const { query, variables, operationName } = request
const formattedRequest = {
variables,
operationName,
query: print(query)
}

const payload = `${timestamp}.${canonicalize(formattedRequest)}`
const hmac = createHmac('sha256', args.signatureSecret)
hmac.update(payload)
const digest = hmac.digest('hex')
return {
headers: {
...headers,
signature: `t=${timestamp}, v${version}=${digest}`
}
}
})
}

export function createApolloClient(
args: CreateApolloClientArgs
): ApolloClient<NormalizedCacheObject> {
const httpLink = createHttpLink({
uri: args.graphqlUrl
})

return new ApolloClient({
uri: graphqlUrl,
link: ApolloLink.from([createAuthLink(args), httpLink]),
cache: new InMemoryCache(),
defaultOptions: {
query: {
Expand Down
13 changes: 11 additions & 2 deletions test/integration/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export type TestConfig = Config & {
interactionServer: string
walletAddressUrl: string
keyId: string
signatureSecret: string
signatureVersion: string
}

type EnvConfig = {
Expand All @@ -22,7 +24,10 @@ type EnvConfig = {
GRAPHQL_URL: string
KEY_ID: string
IDP_SECRET: string
SIGNATURE_SECRET: string
SIGNATURE_VERSION: string
}

const REQUIRED_KEYS: (keyof EnvConfig)[] = [
'OPEN_PAYMENTS_URL',
'AUTH_SERVER_DOMAIN',
Expand All @@ -31,7 +36,9 @@ const REQUIRED_KEYS: (keyof EnvConfig)[] = [
'WALLET_ADDRESS_URL',
'GRAPHQL_URL',
'KEY_ID',
'IDP_SECRET'
'IDP_SECRET',
'SIGNATURE_SECRET',
'SIGNATURE_VERSION'
]

const loadEnv = (filePath: string): EnvConfig => {
Expand Down Expand Up @@ -69,7 +76,9 @@ const createConfig = (name: string): TestConfig => {
walletAddressUrl: env.WALLET_ADDRESS_URL,
graphqlUrl: env.GRAPHQL_URL,
keyId: env.KEY_ID,
idpSecret: env.IDP_SECRET
idpSecret: env.IDP_SECRET,
signatureSecret: env.SIGNATURE_SECRET,
signatureVersion: env.SIGNATURE_VERSION
}
}

Expand Down
6 changes: 5 additions & 1 deletion test/integration/lib/mock-ase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export class MockASE {
// Use static MockASE.create instead.
private constructor(config: TestConfig) {
this.config = config
this.apolloClient = createApolloClient(config.graphqlUrl)
this.apolloClient = createApolloClient({
graphqlUrl: config.graphqlUrl,
signatureSecret: config.signatureSecret,
signatureVersion: config.signatureVersion
})
this.adminClient = new AdminClient(this.apolloClient)
this.accounts = new AccountProvider()
this.integrationServer = new IntegrationServer(
Expand Down
2 changes: 2 additions & 0 deletions test/integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
"@types/koa-bodyparser": "^4.3.12",
"@types/node": "^20.14.15",
"dotenv": "^16.4.5",
"graphql": "^16.8.1",
"hostile": "^1.4.0",
"json-canonicalize": "^1.0.6",
"koa": "^2.15.3",
"mock-account-service-lib": "workspace:*",
"yaml": "^2.6.0"
Expand Down
2 changes: 2 additions & 0 deletions test/integration/testenv/cloud-nine-wallet/.env
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ INTEGRATION_SERVER_PORT=8888
WALLET_ADDRESS_URL=https://cloud-nine-wallet-test-backend:3100/.well-known/pay
GRAPHQL_URL=http://cloud-nine-wallet-test-backend:3101/graphql
IDP_SECRET=2pEcn2kkCclbOHQiGNEwhJ0rucATZhrA807HTm2rNXE=
SIGNATURE_VERSION=1
SIGNATURE_SECRET=iyIgCprjb9uL8wFckR+pLEkJWMB7FJhgkvqhTQR/964=
# matches pfry key id
KEY_ID=keyid-97a3a431-8ee1-48fc-ac85-70e2f5eba8e5
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ services:
USE_TIGERBEETLE: false
OPERATOR_TENANT_ID: 438fa74a-fa7d-4317-9ced-dde32ece1787
API_SECRET: iyIgCprjb9uL8wFckR+pLEkJWMB7FJhgkvqhTQR/964=
API_SIGNATURE_VERSION: 1
volumes:
- ../private-key.pem:/workspace/private-key.pem
depends_on:
Expand Down
2 changes: 2 additions & 0 deletions test/integration/testenv/happy-life-bank/.env
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ INTEGRATION_SERVER_PORT=8889
WALLET_ADDRESS_URL=https://happy-life-bank-test-backend:4100/accounts/pfry
GRAPHQL_URL=http://happy-life-bank-test-backend:4101/graphql
IDP_SECRET=2pEcn2kkCclbOHQiGNEwhJ0rucATZhrA807HTm2rNXE=
SIGNATURE_VERSION=1
SIGNATURE_SECRET=iyIgCprjb9uL8wFckR+pLEkJWMB7FJhgkvqhTQR/964=
# matches pfry key id
KEY_ID=keyid-97a3a431-8ee1-48fc-ac85-70e2f5eba8e5
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ services:
USE_TIGERBEETLE: false
OPERATOR_TENANT_ID: cf5fd7d3-1eb1-4041-8e43-ba45747e9e5d
API_SECRET: iyIgCprjb9uL8wFckR+pLEkJWMB7FJhgkvqhTQR/964=
API_SIGNATURE_VERSION: 1
volumes:
- ../private-key.pem:/workspace/private-key.pem
depends_on:
Expand Down

0 comments on commit db5d0e9

Please sign in to comment.