Skip to content

Commit

Permalink
test: add revocation scenario
Browse files Browse the repository at this point in the history
Signed-off-by: Allain Magyar <allain.magyar@iohk.io>
  • Loading branch information
amagyar-iohk committed May 6, 2024
1 parent 76f4f48 commit 494050d
Show file tree
Hide file tree
Showing 19 changed files with 752 additions and 163 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature: Provide anoncred proof

Scenario: Edge Agent with a credential should provide proof to Cloud Agent
Given Cloud Agent is connected to Edge Agent
And Edge Agent has 1 anonymous credentials issued by Cloud Agent
And Edge Agent has '1' anonymous credentials issued by Cloud Agent
When Cloud Agent asks for presentation of AnonCred proof
And Edge Agent sends the present-proof
Then Cloud Agent should see the present-proof is verified
2 changes: 1 addition & 1 deletion integration-tests/e2e-tests/features/provide_proof.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature: Provide proof

Scenario: Edge Agent with a credential should provide proof to Cloud Agent
Given Cloud Agent is connected to Edge Agent
And Edge Agent has 1 credentials issued by Cloud Agent
And Edge Agent has '1' jwt credentials issued by Cloud Agent
When Cloud Agent asks for present-proof
And Edge Agent sends the present-proof
Then Cloud Agent should see the present-proof is verified
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
@anoncred
@credential
@anoncred @credential
Feature: Receive Anoncred Credential
The Edge Agent should be able to receive an anonymous credential from Cloud Agent

Scenario: Receive one anonymous credential
Given Cloud Agent is connected to Edge Agent
When Cloud Agent offers an anonymous credential
Then Edge Agent should receive the credential
When Edge Agent accepts the credential
And Cloud Agent should see the credential was accepted
Then Edge Agent wait to receive 1 issued credentials
And Edge Agent process 1 issued credentials
When Cloud Agent offers '1' anonymous credential
Then Edge Agent should receive the credentials offer from Cloud Agent
When Edge Agent accepts the credentials offer from Cloud Agent
And Cloud Agent should see all credentials were accepted
Then Edge Agent wait to receive issued credentials from Cloud Agent
And Edge Agent process issued credentials from Cloud Agent
27 changes: 13 additions & 14 deletions integration-tests/e2e-tests/features/receive_jwt_credential.feature
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
@jwt
@credential
@jwt @credential
Feature: Receive JWT Credential
The Edge Agent should be able to receive a verifiable credential from Cloud Agent

Scenario: Receive one verifiable credential
Given Cloud Agent is connected to Edge Agent
When Cloud Agent offers a credential
Then Edge Agent should receive the credential
When Edge Agent accepts the credential
And Cloud Agent should see the credential was accepted
Then Edge Agent wait to receive 1 issued credentials
And Edge Agent process 1 issued credentials
When Cloud Agent offers '1' jwt credentials
Then Edge Agent should receive the credentials offer from Cloud Agent
When Edge Agent accepts the credentials offer from Cloud Agent
And Cloud Agent should see all credentials were accepted
Then Edge Agent wait to receive issued credentials from Cloud Agent
And Edge Agent process issued credentials from Cloud Agent

Scenario: Receive multiple verifiable credentials sequentially
Given Cloud Agent is connected to Edge Agent
When Edge Agent accepts 3 credential offer sequentially from Cloud Agent
When Edge Agent accepts 3 jwt credential offer sequentially from Cloud Agent
Then Cloud Agent should see all credentials were accepted
And Edge Agent wait to receive 3 issued credentials
And Edge Agent process 3 issued credentials
And Edge Agent wait to receive issued credentials from Cloud Agent
And Edge Agent process issued credentials from Cloud Agent

Scenario: Receive multiple verifiable credentials at once
Given Cloud Agent is connected to Edge Agent
When Edge Agent accepts 3 credentials offer at once from Cloud Agent
When Edge Agent accepts 3 jwt credentials offer at once from Cloud Agent
Then Cloud Agent should see all credentials were accepted
And Edge Agent wait to receive 3 issued credentials
And Edge Agent process 3 issued credentials
And Edge Agent wait to receive issued credentials from Cloud Agent
And Edge Agent process issued credentials from Cloud Agent
11 changes: 11 additions & 0 deletions integration-tests/e2e-tests/features/revoke_jwt_credential.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@jwt @revocation
Feature: Revoke JWT Credential
Edge Agent should be notified when Cloud Agent revokes a credential

Scenario: Revoke one verifiable credential
Given Cloud Agent is connected to Edge Agent
And Edge Agent has '1' jwt credentials issued by Cloud Agent
When Cloud Agent revokes '1' credentials
Then Edge Agent waits to receive the revocation notifications from Cloud Agent
And Edge Agent should see the credentials were revoked by Cloud Agent

2 changes: 1 addition & 1 deletion integration-tests/e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"homepage": "https://github.com/input-output-hk/atala-prism-wallet-sdk-ts-e2e",
"dependencies": {
"@atala/prism-wallet-sdk": "^5.0.0",
"@atala/prism-wallet-sdk": "../../",
"@cucumber/cucumber": "^10.3.1",
"@cucumber/pretty-formatter": "^1.0.0",
"@hyperledger-labs/open-enterprise-agent-ts-client": "^1.31.0",
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/e2e-tests/src/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { appendFile, writeFileSync } from "fs"
import crypto from "crypto"

export class Utils {
static async asyncFilter<T>(arr: T[], predicate: (value: T, index: number, array: T[]) => Promise<boolean>) {
const results = await Promise.all(arr.map(predicate))
return arr.filter((_v, index) => results[index])
}

static prepareNotes() {
writeFileSync("notes", "### End-to-end notes:\n\n")
}
Expand Down
38 changes: 31 additions & 7 deletions integration-tests/e2e-tests/src/abilities/WalletSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@ import { Message } from "@atala/prism-wallet-sdk/build/typings/domain"
import axios from "axios"
import { CloudAgentConfiguration } from "../configuration/CloudAgentConfiguration"
import { Utils } from "../Utils"
import { InMemoryStore } from "../configuration/InMemoryStore"
import InMemoryStore from "../configuration/inmemory"

const { Agent, Apollo, Domain, ListenerKey, } = SDK

export class WalletSdk extends Ability implements Initialisable, Discardable {
sdk!: SDK.Agent
store: SDK.Store
messages: MessageQueue = new MessageQueue()

static async withANewInstance(): Promise<Ability> {
const instance: SDK.Agent = await Utils.retry(2, async () => {
const {sdk, store} = await Utils.retry(2, async () => {
return await WalletSdkBuilder.createInstance()
})
return new WalletSdk(instance)
return new WalletSdk(sdk, store)
}

constructor(sdk: SDK.Agent) {
constructor(sdk: SDK.Agent, store: SDK.Store) {
super()
this.sdk = sdk
this.store = store
}

static credentialOfferStackSize(): QuestionAdapter<number> {
Expand All @@ -42,21 +44,30 @@ export class WalletSdk extends Ability implements Initialisable, Discardable {
})
}

static revocationStackSize(): QuestionAdapter<number> {
return Question.about("revocation messages stack", actor => {
return WalletSdk.as(actor).messages.revocationStack.length
})
}

static execute(callback: (sdk: SDK.Agent, messages: {
credentialOfferStack: Message[];
issuedCredentialStack: Message[];
proofRequestStack: Message[];
revocationStack: Message[],
}) => Promise<void>): Interaction {
return Interaction.where("#actor uses wallet sdk", async actor => {
await callback(WalletSdk.as(actor).sdk, {
credentialOfferStack: WalletSdk.as(actor).messages.credentialOfferStack,
issuedCredentialStack: WalletSdk.as(actor).messages.issuedCredentialStack,
proofRequestStack: WalletSdk.as(actor).messages.proofRequestStack
proofRequestStack: WalletSdk.as(actor).messages.proofRequestStack,
revocationStack: WalletSdk.as(actor).messages.revocationStack,
})
})
}

async discard(): Promise<void> {
await this.store.clear()
await this.sdk.stop()
}

Expand Down Expand Up @@ -87,11 +98,19 @@ class WalletSdkBuilder {

static async createInstance() {
const apollo = new Apollo()
const store = new InMemoryStore()
const store = new SDK.Store({
name: [...Array(30)].map(() => Math.random().toString(36)[2]).join(""),
storage: InMemoryStore,
password: "random12434",
ignoreDuplicate: true
})
const pluto = new SDK.Pluto(store, apollo)
const mediatorDID = Domain.DID.fromString(await WalletSdkBuilder.getMediatorDidThroughOob())

return Agent.initialize({ apollo, pluto, mediatorDID })
return {
sdk: Agent.initialize({ apollo, pluto, mediatorDID }),
store
}
}
}

Expand All @@ -105,8 +124,10 @@ class MessageQueue {
credentialOfferStack: Message[] = []
proofRequestStack: Message[] = []
issuedCredentialStack: Message[] = []
revocationStack: Message[] = []
receivedMessages: string[] = []


enqueue(message: Message) {
this.queue.push(message)

Expand Down Expand Up @@ -134,6 +155,7 @@ class MessageQueue {
this.processingId = setInterval(() => {
if (!this.isEmpty()) {
const message: Message = this.dequeue()

// checks if sdk already received message
if (this.receivedMessages.includes(message.id)) {
return
Expand All @@ -147,6 +169,8 @@ class MessageQueue {
this.proofRequestStack.push(message)
} else if (message.piuri.includes("/issue-credential")) {
this.issuedCredentialStack.push(message)
} else if (message.piuri.includes("/revoke")) {
this.revocationStack.push(message)
}
} else {
clearInterval(this.processingId!)
Expand Down
63 changes: 0 additions & 63 deletions integration-tests/e2e-tests/src/configuration/InMemoryStore.ts

This file was deleted.

16 changes: 16 additions & 0 deletions integration-tests/e2e-tests/src/configuration/inmemory/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { randomUUID } from "crypto";
import SDK from "@atala/prism-wallet-sdk";
import InMemoryStore from "./index";


export const mockPluto = (args?: { apollo: SDK.Apollo; }) => {
const apollo = args?.apollo ?? new SDK.Apollo();

const store = new SDK.Store({
name: 'test' + randomUUID(),
storage: InMemoryStore,
password: Buffer.from("demoapp").toString("hex")
});

return new SDK.Pluto(store, apollo);
};
44 changes: 44 additions & 0 deletions integration-tests/e2e-tests/src/configuration/inmemory/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { type RxStorage, RxStorageDefaultStatics, type RxStorageInstance, type RxStorageInstanceCreationParams, newRxError } from 'rxdb'
import { type InMemorySettings, type InMemoryStorageInternals, type RxStorageInMemoryType } from './types'
import { RxStorageIntanceInMemory } from './instance'
import { InMemoryInternal } from './internal'

const internalInstance = new Map<string, InMemoryInternal<any>>()

function getRxStorageMemory<RxDocType>(settings: InMemorySettings = {}): RxStorageInMemoryType<RxDocType> {
const inMemoryInstance: RxStorageInMemoryType<any> = {
name: 'in-memory',
statics: RxStorageDefaultStatics,
async createStorageInstance<RxDocType>(params: RxStorageInstanceCreationParams<RxDocType, InMemorySettings>): Promise<RxStorageInstance<RxDocType, InMemoryStorageInternals<RxDocType>, InMemorySettings, any>> {
if (params.schema.keyCompression) {
throw newRxError('UT5', { args: { databaseName: params.databaseName, collectionName: params.collectionName } })
}
const existingInstance = internalInstance.get(params.databaseName)
if (!existingInstance) {
internalInstance.set(params.databaseName, new InMemoryInternal<RxDocType>(0))
} else {
existingInstance.refCount++
internalInstance.set(params.databaseName, existingInstance)
}
return new RxStorageIntanceInMemory(
this,
params.databaseName,
params.collectionName,
params.schema,
internalInstance.get(params.databaseName)!,
settings
)
}
}
return inMemoryInstance
}

/**
* InMemory storage
* @description Use this as storage in our RXDB database. For now there is no initialisation settings, so you can use it out of the box.
*/
const storage: RxStorage<any, any> = getRxStorageMemory()

export default storage


0 comments on commit 494050d

Please sign in to comment.