Skip to content

Commit

Permalink
Legacy request translation (#135)
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel authored Mar 4, 2024
1 parent 485481c commit 5cd9c9d
Show file tree
Hide file tree
Showing 14 changed files with 595 additions and 300 deletions.
4 changes: 4 additions & 0 deletions apps/policy-engine/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ policy-engine/rego/translate:
ts-node -r tsconfig-paths/register \
--project ${POLICY_ENGINE_PROJECT_DIR}/tsconfig.app.json ${POLICY_ENGINE_PROJECT_DIR}/src/opa/script/translate-legacy-policy.script.ts

policy-engine/rego/evaluation:
npx dotenv -e ${POLICY_ENGINE_PROJECT_DIR}/.env -- \
ts-node -r tsconfig-paths/register \
--project ${POLICY_ENGINE_PROJECT_DIR}/tsconfig.app.json ${POLICY_ENGINE_PROJECT_DIR}/src/opa/script/evaluate-legacy-policy.script.ts

policy-engine/rego/test:
opa test \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ test_checkSignTypedData {
with data.entities as entities

checkIntentDomain({
"chainId": {"1", "137"},
"name": {"UNI", "LINK"},
"verifyingContract": {"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"},
"chainId": ["1", "137"],
"name": ["UNI", "LINK"],
"verifyingContract": ["eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"],
}) with input as signTypedDataRequest with data.entities as entities
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,32 +28,34 @@ checkIntentPayload(condition) {

# Intent Sign Raw Payload Algorithm

checkIntentAlgorithm(values) = input.intent.algorithm in values
checkIntentAlgorithm(values) {
input.intent.algorithm in values
}

# Intent Sign Typed Data Domain

checkDomainCondition(value, set) {
set == wildcard
checkDomainCondition(value, arr) {
arr == wildcard
}

checkDomainCondition(value, set) {
set != wildcard
value in set
checkDomainCondition(value, arr) {
arr != wildcard
value in arr
}

checkIntentDomain(filters) {
conditions = object.union(
{
"version": wildcard,
"chainId": wildcard,
"name": wildcard,
"verifyingContract": wildcard,
},
filters,
)

checkDomainCondition(input.intent.domain.version, conditions.version)
checkDomainCondition(numberToString(input.intent.domain.chainId), conditions.chainId)
checkDomainCondition(input.intent.domain.name, conditions.name)
checkDomainCondition(input.intent.domain.verifyingContract, conditions.verifyingContract)
wildcardDomain = {
"version": wildcard,
"chainId": wildcard,
"name": wildcard,
"verifyingContract": wildcard,
}

domain = object.union(wildcardDomain, input.intent.domain)
conditions = object.union(wildcardDomain, filters)

checkDomainCondition(domain.version, conditions.version)
checkDomainCondition(numberToString(domain.chainId), conditions.chainId)
checkDomainCondition(domain.name, conditions.name)
checkDomainCondition(domain.verifyingContract, conditions.verifyingContract)
}
11 changes: 11 additions & 0 deletions apps/policy-engine/src/opa/rego/policies/missing-rules.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

permit[{"policyId": "call-contract-custom", "policyName": "call-contract-custom"}] = reason {
checkResourceIntegrity
checkAction({"signTransaction"})
checkIntentType({"callContract"})
checkPrincipalId({"auth0|62e1d7ca04533b042cb42419"})
checkIntentContract({"eip155:137:0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"})
checkChainId({"137"})
reason = {"type": "permit", "policyId": "call-contract-custom", "policyName": "call-contract-custom", "approvalsSatisfied": [], "approvalsMissing": []}
}
150 changes: 150 additions & 0 deletions apps/policy-engine/src/opa/script/evaluate-legacy-policy.script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Action, Request, UserRole } from '@narval/policy-engine-shared'
import { InputType, safeDecode } from '@narval/transaction-request-intent'
import { loadPolicy } from '@open-policy-agent/opa-wasm'
import { readFileSync } from 'fs'
import path from 'path'
import { OpaResult, RegoInput } from '../../shared/types/domain.type'

export const evaluate = async (users: any[], wallets: any[], legacyActivityRequests: any[]) => {
const entities: { [key: string]: any } = { users: {}, wallets: {} }

for (const user of users) {
let role = user.guildUserRole

if (['SCHOLAR'].includes(role)) {
role = UserRole.MEMBER
} else if (['ADMIN', 'API'].includes(role)) {
role = UserRole.ADMIN
}

entities.users[user.id] = { id: user.id, role }
}

for (const wallet of wallets) {
const uid = `eip155:${wallet.accountType}:${wallet.address}`

entities.wallets[uid] = {
uid,
address: wallet.address,
accountType: wallet.accountType,
assignees: wallet.assignees?.map((assignee: any) => assignee.userId) || []
}
}

const requests = legacyActivityRequests.filter(
({ initiator_user_id }) => undefined !== entities.users[initiator_user_id]
) as {
status: string
initiator_user_id: string
request: Request
}[]

for (const { status, initiator_user_id, request } of requests) {
let input = {} as RegoInput

if (request.action === Action.SIGN_TRANSACTION) {
const intentResult = safeDecode({
input: {
type: InputType.TRANSACTION_REQUEST,
txRequest: request.transactionRequest
}
})

if (intentResult?.success === false) {
console.log(
`Could not decode intent: ${intentResult.error.message}`,
JSON.stringify(request.transactionRequest, null, 2)
)
continue
}

input = {
action: request.action,
intent: intentResult?.intent,
transactionRequest: request.transactionRequest,
principal: {
id: initiator_user_id,
userId: initiator_user_id,
alg: 'ES256K',
pubKey: ''
},
resource: request.resourceId ? { uid: request.resourceId } : undefined,
approvals: []
}
}

if (request.action === Action.SIGN_MESSAGE) {
const intentResult = safeDecode({
input: {
type: InputType.MESSAGE,
payload: request.message
}
})

if (intentResult?.success === false) {
console.log(`Could not decode intent: ${intentResult.error.message}`, JSON.stringify(request.message, null, 2))
continue
}

input = {
action: request.action,
intent: intentResult?.intent,
principal: {
id: initiator_user_id,
userId: initiator_user_id,
alg: 'ES256K',
pubKey: ''
},
resource: request.resourceId ? { uid: request.resourceId } : undefined,
approvals: []
}
}

if (request.action === Action.SIGN_TYPED_DATA) {
const intentResult = safeDecode({
input: {
type: InputType.TYPED_DATA,
typedData: JSON.parse(request.typedData)
}
})

if (intentResult?.success === false) {
console.log(
`Could not decode intent: ${intentResult.error.message}`,
JSON.stringify(request.typedData, null, 2)
)
continue
}

input = {
action: request.action,
intent: intentResult?.intent,
principal: {
id: initiator_user_id,
userId: initiator_user_id,
alg: 'ES256K',
pubKey: ''
},
resource: request.resourceId ? { uid: request.resourceId } : undefined,
approvals: []
}
}

const OPA_WASM_PATH = path.join(process.cwd(), './rego-build/policy.wasm')
const policyWasm = readFileSync(OPA_WASM_PATH)
const opaEngine = await loadPolicy(policyWasm, undefined, { 'time.now_ns': () => new Date().getTime() * 1000000 })
opaEngine.setData({ entities })

const evalResult: { result: OpaResult }[] = await opaEngine.evaluate(input, 'main/evaluate')
const results = evalResult.map(({ result }) => result)

if (status == 'completed' && !results[0].permit) {
console.log({ id: results[0].reasons.map((reason) => reason.policyName), status, result: results[0].permit })
}
}
}

// evaluate(users, wallets, requests)
// .then(() => console.log('done'))
// .catch((error) => console.log('error', error))
Loading

0 comments on commit 5cd9c9d

Please sign in to comment.