Skip to content

Commit

Permalink
Add support to sign typed data (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcalderipe authored Apr 5, 2024
1 parent a0699dd commit 0a00135
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 208 deletions.
274 changes: 85 additions & 189 deletions apps/policy-engine/src/engine/__test__/e2e/evaluation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import { getTestRawAesKeyring } from '../../../shared/testing/encryption.testing
import {
generateSignMessageRequest,
generateSignRawRequest,
generateSignTransactionRequest
generateSignTransactionRequest,
generateSignTypedDataRequest
} from '../../../shared/testing/evaluation.testing'
import { Client } from '../../../shared/type/domain.type'
import { ClientService } from '../../core/service/client.service'
Expand Down Expand Up @@ -118,209 +119,104 @@ describe('Evaluation', () => {
})

describe('POST /evaluations', () => {
describe('when sign transaction', () => {
it('evaluates a forbid', async () => {
const payload = await generateSignTransactionRequest()

const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)

expect(body).toEqual({
decision: Decision.FORBID,
request: payload.request
})
expect(status).toEqual(HttpStatus.OK)
})

it('evaluates a permit', async () => {
await clientService.savePolicyStore(
client.clientId,
await getPolicyStore(
[
{
id: 'test-permit-policy',
then: Then.PERMIT,
description: 'test permit policy',
when: [
{
criterion: Criterion.CHECK_ACTION,
args: [Action.SIGN_TRANSACTION]
}
]
}
],
privateKey
)
)

const payload = await generateSignTransactionRequest()
it('responds with forbid when client secret is missing', async () => {
const payload = await generateSignTransactionRequest()

const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)
const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.send(payload)

expect(body).toMatchObject({
decision: Decision.PERMIT,
request: payload.request,
accessToken: {
value: expect.any(String)
},
approvals: {
missing: [],
required: [],
satisfied: []
}
})
expect(status).toEqual(HttpStatus.OK)
expect(body).toEqual({
message: `Missing or invalid ${REQUEST_HEADER_CLIENT_SECRET} header`,
statusCode: HttpStatus.UNAUTHORIZED
})
expect(status).toEqual(HttpStatus.UNAUTHORIZED)
})

describe('when sign message ', () => {
let payload: EvaluationRequest

beforeEach(async () => {
payload = await generateSignMessageRequest()
})

it('evaluates a forbid', async () => {
const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)

expect(body).toEqual({
decision: Decision.FORBID,
request: payload.request
})
expect(status).toEqual(HttpStatus.OK)
})

it('evaluates a permit', async () => {
await clientService.savePolicyStore(
client.clientId,
await getPolicyStore(
[
{
id: 'test-permit-policy',
then: Then.PERMIT,
description: 'test permit policy',
when: [
{
criterion: Criterion.CHECK_ACTION,
args: [Action.SIGN_MESSAGE]
}
]
}
],
privateKey
)
)
const useCases = [
{
action: Action.SIGN_TRANSACTION,
getPayload: () => generateSignTransactionRequest()
},
{
action: Action.SIGN_TYPED_DATA,
getPayload: () => generateSignTypedDataRequest()
},
{
action: Action.SIGN_MESSAGE,
getPayload: () => generateSignMessageRequest()
},
{
action: Action.SIGN_RAW,
getPayload: () => generateSignRawRequest()
}
]

const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)
useCases.forEach(({ action, getPayload }) => {
describe(`when action is ${action}`, () => {
let payload: EvaluationRequest

expect(body).toMatchObject({
decision: Decision.PERMIT,
request: payload.request,
accessToken: {
value: expect.any(String)
},
approvals: {
missing: [],
required: [],
satisfied: []
}
beforeEach(async () => {
payload = await getPayload()
})
expect(status).toEqual(HttpStatus.OK)
})
})

describe('when sign raw', () => {
let payload: EvaluationRequest

beforeEach(async () => {
payload = await generateSignRawRequest()
})

it('evaluates a forbid', async () => {
const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)

expect(body).toEqual({
decision: Decision.FORBID,
request: payload.request
it('evaluates a forbid', async () => {
const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)

expect(body).toEqual({
decision: Decision.FORBID,
request: payload.request
})
expect(status).toEqual(HttpStatus.OK)
})
expect(status).toEqual(HttpStatus.OK)
})

it('evaluates a permit', async () => {
await clientService.savePolicyStore(
client.clientId,
await getPolicyStore(
[
{
id: 'test-permit-policy',
then: Then.PERMIT,
description: 'test permit policy',
when: [
{
criterion: Criterion.CHECK_ACTION,
args: [Action.SIGN_RAW]
}
]
}
],
privateKey
it('evaluates a permit', async () => {
await clientService.savePolicyStore(
client.clientId,
await getPolicyStore(
[
{
id: 'test-permit-policy',
then: Then.PERMIT,
description: 'test permit policy',
when: [
{
criterion: Criterion.CHECK_ACTION,
args: [action]
}
]
}
],
privateKey
)
)
)

const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)

expect(body).toMatchObject({
decision: Decision.PERMIT,
request: payload.request,
accessToken: {
value: expect.any(String)
},
approvals: {
missing: [],
required: [],
satisfied: []
}
const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.set(REQUEST_HEADER_CLIENT_SECRET, client.clientSecret)
.send(payload)

expect(body).toMatchObject({
decision: Decision.PERMIT,
request: payload.request,
accessToken: {
value: expect.any(String)
},
approvals: {
missing: [],
required: [],
satisfied: []
}
})
expect(status).toEqual(HttpStatus.OK)
})
expect(status).toEqual(HttpStatus.OK)
})
})

it('responds with forbid when client secret is missing', async () => {
const payload = await generateSignTransactionRequest()

const { status, body } = await request(app.getHttpServer())
.post('/evaluations')
.set(REQUEST_HEADER_CLIENT_ID, client.clientId)
.send(payload)

expect(body).toEqual({
message: `Missing or invalid ${REQUEST_HEADER_CLIENT_SECRET} header`,
statusCode: HttpStatus.UNAUTHORIZED
})
expect(status).toEqual(HttpStatus.UNAUTHORIZED)
})
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
Action,
ApprovalRequirement,
CredentialEntity,
Decision,
Expand All @@ -25,8 +24,6 @@ import { toData, toInput } from './util/evaluation.util'
import { getRegoRuleTemplatePath } from './util/rego-transpiler.util'
import { build, getRegoCorePath } from './util/wasm-build.util'

const SUPPORTED_ACTIONS: Action[] = [Action.SIGN_MESSAGE, Action.SIGN_TRANSACTION, Action.SIGN_RAW]

export class OpenPolicyAgentEngine implements Engine<OpenPolicyAgentEngine> {
private policies: Policy[]

Expand Down Expand Up @@ -108,16 +105,6 @@ export class OpenPolicyAgentEngine implements Engine<OpenPolicyAgentEngine> {
}

async evaluate(evaluation: EvaluationRequest): Promise<EvaluationResponse> {
const { action } = evaluation.request

if (!SUPPORTED_ACTIONS.includes(action)) {
throw new OpenPolicyAgentException({
message: 'Open Policy Agent engine unsupported action',
suggestedHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
context: { action }
})
}

const message = hash(evaluation.request)
const principalCredential = await this.verifySignature(evaluation.authentication, message)

Expand Down
Loading

0 comments on commit 0a00135

Please sign in to comment.