Skip to content

Commit

Permalink
set policies and entities, tested with devtool
Browse files Browse the repository at this point in the history
  • Loading branch information
Ptroger committed May 13, 2024
1 parent 785d611 commit e7f257c
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 14 deletions.
26 changes: 23 additions & 3 deletions packages/armory-sdk/src/lib/domain.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { AccessToken, Decision, Request, addressSchema, hexSchema } from '@narval/policy-engine-shared'
import { Payload, jwkSchema } from '@narval/signature'
import {
AccessToken,
Decision,
EntityData,
Request,
addressSchema,
hexSchema,
policySchema
} from '@narval/policy-engine-shared'
import { Payload, jwkSchema, privateKeySchema } from '@narval/signature'
import { z } from 'zod'

export const Endpoints = {
engine: {
evaluations: '/evaluations'
evaluations: '/evaluations',
sync: '/clients/sync'
},
vault: {
sign: '/sign',
Expand Down Expand Up @@ -126,3 +135,14 @@ export const Permission = {
} as const
export type Permission = (typeof Permission)[keyof typeof Permission]
export const PermissionSchema = z.nativeEnum(Permission)
export const SetPolicyRequest = z.object({
policies: z.array(policySchema),
privateKey: privateKeySchema
})
export type SetPolicyRequest = z.infer<typeof SetPolicyRequest>

export const SetEntityRequest = z.object({
entity: EntityData,
privateKey: privateKeySchema
})
export type SetEntityRequest = z.infer<typeof SetEntityRequest>
113 changes: 112 additions & 1 deletion packages/armory-sdk/src/lib/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Request } from '@narval/policy-engine-shared'
import { EntityStore, PolicyStore, Request } from '@narval/policy-engine-shared'
import axios from 'axios'
import {
ArmoryClientConfig,
ArmoryClientConfigInput,
Expand All @@ -8,17 +9,22 @@ import {
ImportPrivateKeyRequest,
ImportPrivateKeyResponse,
SdkEvaluationResponse,
SetEntityRequest,
SetPolicyRequest,
SignatureRequest,
SignatureResponse,
VaultClientConfig
} from './domain'
import { NarvalSdkException } from './exceptions'
import { sendEvaluationRequest } from './http/policy-engine'
import { sendImportPrivateKey, sendSignatureRequest } from './http/vault'
import {
buildBasicEngineHeaders,
buildBasicVaultHeaders,
buildGnapVaultHeaders,
checkDecision,
signAccountJwsd,
signData,
signRequest as signRequestHelper,
walletId
} from './utils'
Expand Down Expand Up @@ -130,3 +136,108 @@ export const signRequest = async (config: VaultClientConfig, input: SignatureReq

return data
}

export const syncEngine = async (config: EngineClientConfig) => {
const { authHost } = config
const headers = buildBasicEngineHeaders(config)

const { data } = await axios.post(`${authHost}${Endpoints.engine.sync}`, null, {
headers
})
if (!data.ok) {
throw new NarvalSdkException('Failed to sync engine', {
config,
engineError: data
})
}
}

export const setPolicies = async (
config: EngineClientConfig & {
policyStoreHost: string
},
input: SetPolicyRequest
): Promise<{ success: boolean }> => {
const headers = buildBasicEngineHeaders(config)
const { privateKey, policies } = input
const { policyStoreHost } = config

const signature = await signData(privateKey, policies, {
sub: privateKey.kid,
iss: config.authClientId
})

const policy: PolicyStore = {
data: input.policies,
signature
}

try {
const res = await axios.post(policyStoreHost, { policy }, { headers })
if (res.status !== 200) {
throw new NarvalSdkException('Failed to set policies', {
config,
input,
storeResponse: res.data
})
}
} catch (error) {
throw new NarvalSdkException('Failed to set policies', {
config,
input,
error
})
}
try {
await syncEngine(config)
return { success: true }
} catch (error) {
throw new NarvalSdkException('Failed to sync engine after setting policies', {
config,
input,
error
})
}
}

export const setEntities = async (
config: EngineClientConfig & {
entityStoreHost: string
},
input: SetEntityRequest
): Promise<{ success: boolean }> => {
const headers = buildBasicEngineHeaders(config)
const { privateKey, entity: entities } = input

const { entityStoreHost } = config

const signature = await signData(privateKey, entities, {
sub: privateKey.kid,
iss: config.authClientId
})

const entity: EntityStore = {
data: entities.entity.data,
signature
}

const res = await axios.post(entityStoreHost, { entity }, { headers })
if (res.status !== 200) {
throw new NarvalSdkException('Failed to set entities', {
config,
input,
storeResponse: res.data
})
}
try {
await syncEngine(config)
return { success: true }
} catch (error) {
throw new NarvalSdkException('Failed to sync engine after setting entities', {
config,
input,
error,
storeResponse: res.data
})
}
}
44 changes: 34 additions & 10 deletions packages/armory-sdk/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ import {
Request,
isAddress
} from '@narval/policy-engine-shared'
import { JwsdHeader, Payload, buildSignerForAlg, hash, hexToBase64Url, signJwsd, signJwt } from '@narval/signature'
import {
JwsdHeader,
Payload,
PrivateKey,
buildSignerForAlg,
hash,
hexToBase64Url,
signJwsd,
signJwt
} from '@narval/signature'
import { v4 } from 'uuid'
import { Address } from 'viem'
import {
Expand Down Expand Up @@ -79,20 +88,35 @@ export const signRequest = async (config: EngineClientConfig, request: Request):
}
}

export const buildDataPayload = (config: EngineClientConfig, data: unknown): Payload => {
export const buildDataPayload = (
data: unknown,
opts: {
iss?: string
sub?: string
iat?: number
} = {}
): Payload => {
const hashed = hash(data)
return {
data: hashed,
sub: config.signer.kid,
iss: config.authClientId,
iat: new Date().getTime()
sub: opts.sub,
iss: opts.iss,
iat: opts.iat || new Date().getTime()
}
}

export const signData = async (config: EngineClientConfig, data: unknown): Promise<JwtString> => {
const payload = buildDataPayload(config, data)

const authentication = await signJwt(payload, config.signer)
export const signData = async (
signer: PrivateKey,
data: unknown,
opts: {
iss?: string
sub?: string
iat?: number
} = {}
): Promise<JwtString> => {
const payload = buildDataPayload(data, opts)

const authentication = await signJwt(payload, signer)
return authentication
}

Expand Down Expand Up @@ -133,7 +157,7 @@ export const walletId = (input: ImportPrivateKeyRequest): ImportPrivateKeyReques
return input
}

export const buildBasicAuthHeaders = (config: EngineClientConfig): BasicHeaders => {
export const buildBasicEngineHeaders = (config: EngineClientConfig): BasicHeaders => {
return {
'x-client-id': config.authClientId,
'x-client-secret': config.authSecret
Expand Down

0 comments on commit e7f257c

Please sign in to comment.