diff --git a/Directory.Build.props b/Directory.Build.props index 87fc28c1..806d741b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -21,7 +21,7 @@ false - netstandard2.1 + net8.0 @@ -41,8 +41,6 @@ 9.2.0 9.2.0 2.8.2 - 2.0.1 - 0.4.2-alpha 8.0.1 8.0.2 4.0.0 diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 00000000..af5a0e72 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,11 @@ + + + + <_LegacyRefs Include="@(ProjectReference)" + Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(ProjectReference.Identity)', '(?i)[/\\\\]legacy[/\\\\]'))" /> + + + + + diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 21249d6e..671da971 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -7,4 +7,3 @@ | Christopher Hempel | [@CHempel-esatus](https://github.com/CHempel-esatus) | CHempel_esatus#6640 | | Kevin Dinh | [@Dindexx](https://github.com/Dindexx) | | | Johannes Türk | [@JoTiTu](https://github.com/JoTiTu) | | -| Ken Kosmowski | [@kenkosmowski](https://github.com/kenkosmowski) | | diff --git a/README.md b/README.md index ec675bfa..52c136f2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Wallet Framework for .NET -Wallet Framework for .NET is an open framework for building digital identity wallets. The framework was initiated as [Aries Framework .NET](https://github.com/hyperledger/aries-framework-dotnet) in the Hyperledger Foundation and was forked to express the goal to broaden the supported identity protocols, especially with regard to [OID4VC](https://openid.net/openid4vc/) and [SD-JWT](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-selective-disclosure-jwt-05). +Wallet Framework for .NET is an open framework for building digital identity wallets with a focus on [OID4VC](https://openid.net/openid4vc/), [SD-JWT](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-selective-disclosure-jwt-05) and mdoc (ISO/IEC 18013-5). + +The framework was initiated as Aries Framework .NET in the Hyperledger Foundation. The Hyperledger Aries and Indy components have been deprecated, are now considered legacy and will not be supported anymore. ## Table of Contents @@ -8,25 +10,14 @@ Wallet Framework for .NET is an open framework for building digital identity wal - [Roadmap](#roadmap) - [Protocols](#protocols) - [OpenID for Verifiable Credentials (OID4VC)](#openid-for-verifiable-credentials-oid4vc) - - [Hyperledger Aries](#hyperledger-aries) - [Credential Formats](#credential-formats) - - [Quickstart Guide](#quickstart-guide) - - [Prerequisites](#prerequisites) - - [Create new web application](#create-new-web-application) - - [Add the framework dependencies](#add-the-framework-dependencies) - - [Register the agent middleware](#register-the-agent-middleware) - - [Demo](#demo) - - [Testing](#testing) - - [Install libindy library](#install-libindy-library) - - [Run an indy node pool on localhost](#run-an-indy-node-pool-on-localhost) - - [Run an indy node pool on server](#run-an-indy-node-pool-on-server) - - [Run the tests](#run-the-tests) + - [Releases / Versioning](#releases--versioning) - [License](#license) ## Roadmap - OpenID4VC Support - SD-JWT VC Support -- Replacing the indy-sdk +- mdoc Support ## Protocols @@ -48,127 +39,14 @@ Wallet Framework for .NET is an open framework for building digital identity wal | - Verifier Authentication | [Verifier Authentication](https://openid.github.io/OpenID4VP/openid-4-verifiable-presentations-wg-draft.html#name-verifier-metadata-managemen) | :construction: | | **Self-Issued OpenID Provider v2** | [SIOPv2](https://openid.net/specs/openid-connect-self-issued-v2-1_0-ID1.html) | :construction: | -## Hyperledger Aries - -**AIP 1.0** -| Protocol | State | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -| [0019-encryption-envelope](https://github.com/hyperledger/aries-rfcs/tree/9b0aaa39df7e8bd434126c4b33c097aae78d65bf/features/0019-encryption-envelope) | :white_check_mark: | -| [0160-connection-protocol](https://github.com/hyperledger/aries-rfcs/tree/4d9775490359e234ab8d1c152bca6f534e92a38d/features/0160-connection-protocol) | :white_check_mark: | -| [0036-issue-credential](https://github.com/hyperledger/aries-rfcs/tree/bb42a6c35e0d5543718fb36dd099551ab192f7b0/features/0036-issue-credential) | :white_check_mark: | -| [0037-present-proof](https://github.com/hyperledger/aries-rfcs/tree/4fae574c03f9f1013db30bf2c0c676b1122f7149/features/0037-present-proof) | :white_check_mark: | -| [0056-service-decorator](https://github.com/hyperledger/aries-rfcs/tree/527849ec3aa2a8fd47a7bb6c57f918ff8bcb5e8c/features/0056-service-decorator) | :white_check_mark: | -| [0025-didcomm-transports](https://github.com/hyperledger/aries-rfcs/tree/b490ebe492985e1be9804fc0763119238b2e51ab/features/0025-didcomm-transports) | Http supported | -| [0015-acks](https://github.com/hyperledger/aries-rfcs/tree/5cc750f0fe18e3918401489066566f22474e25a8/features/0015-acks) | Partially supported | -| [0035-report-problem](https://github.com/hyperledger/aries-rfcs/tree/89d14c15ab35b667e7a9d04fe42d4d48b10468cf/features/0035-report-problem) | Partially supported | - - -**AIP 2.0** -| Protocol | State | -| ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | -| [0023-did-exchange](https://github.com/hyperledger/aries-rfcs/tree/bf3d796cc33ce78ed7cde7f5422b10719a68be21/features/0023-did-exchange) | :white_check_mark: | -| [0048-trust-ping](https://github.com/hyperledger/aries-rfcs/tree/4e78319e5f79df2003ddf37f8f497d0fae20cc63/features/0048-trust-ping) | :white_check_mark: | -| [0095-basic-message](https://github.com/hyperledger/aries-rfcs/tree/b3a3942ef052039e73cd23d847f42947f8287da2/features/0095-basic-message) | :white_check_mark: | -| | | - ## Credential Formats | Credential Format | Link | State | | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | -| AnonCreds 1.0 | [Anonymous Credential Protocol](https://hyperledger-indy.readthedocs.io/projects/hipe/en/latest/text/0109-anoncreds-protocol/README.html) | :white_check_mark: | | SD-JWT-based Verifiable Credentials | [SD-JWT VC](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-sd-jwt-vc-00) | :construction: | +| mdoc (ISO/IEC 18013-5) | [mdoc](https://www.iso.org/standard/69084.html) | :construction: | -## Quickstart Guide - -The framework fully leverages the [.NET Core hosting model](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.0) with full integration of dependency injection, configuration and hosting services. - -### Prerequisites - -- Install [.NET Core](https://dotnet.microsoft.com/download) -- Install [libindy for your platform](https://github.com/hyperledger/indy-sdk/#installing-the-sdk) - -### Create new web application - -Using your favorite editor, create new web project. You can also create a project from the console. - -```bash -dotnet new web -o AriesAgent -``` - -To setup your agent use the `Startup.cs` file to configure the framework. - -### Add the framework dependencies - -Use the `IServiceCollection` extensions to add the dependent services to your application in the `ConfigureServices(IServiceCollection services)` method. Upon startup, the framework will create and configure your agent. - -```c# -services.AddAriesFramework(builder => -{ - builder.RegisterAgent(options => - { - options.EndpointUri = "http://localhost:5000/"; - }); -}); -``` - -> Note: If you'd like your agent to be accessible publically, use Ngrok to setup a public host and use that as the `EndpointUri`. -> When changing the endpoints, make sure you clear any previous wallets with the old configuration. Wallet data files are located in `~/.indy_client/wallet` - -For a list of all configuration options, check the [AgentOptions.cs](https://github.com/hyperledger/aries-framework-dotnet/blob/master/src/Hyperledger.Aries/Configuration/AgentOptions.cs) file. - -### Register the agent middleware - -When running web applications, register the agent middleware in the `Configure(IApplicationBuilder app, IWebHostEnvironment env)` method. This will setup a middleware in the AspNetCore pipeline that will respond to incoming agent messages. - -```c# -app.UseAriesFramework(); -``` - -That's it. Run your project. - -## Demo - -With [Docker](https://www.docker.com) installed, run - -```lang=bash -docker-compose up -``` - -This will create an agent network with a pool of 4 indy nodes and 2 agents able to communicate with each other in the network. -Navigate to [http://localhost:7000](http://localhost:7000) and [http://localhost:8000](http://localhost:8000) to create and accept connection invitations between the different agents. - - -## Testing - -To run the unit tests, the following dependencies also must be installed: -- Docker - -### Install libindy library -Follow the build instructions for your OS on the [Hyperledger Indy SDK](https://github.com/hyperledger/indy-sdk) Readme. - -For macOS, if you get a `'indy' DLL not found exception`, move the built `libindy.dylib` file to the `test/Hyperledger.Aries.Tests/bin/Debug/netcoreapp3.1/` directory to explicitly add it to the path. - - -### Run an indy node pool on localhost -``` -docker build --build-arg pool_ip=127.0.0.1 -f docker/indy-pool.dockerfile -t indy_pool docker/ -docker run -itd -p 9701-9709:9701-9709 indy_pool -``` - -### Run an indy node pool on server -``` -# replace with server IP address -docker build --build-arg pool_ip= -f docker/indy-pool.dockerfile -t indy_pool docker/ -docker run -itd -p :9701-9709:9701-9709 indy_pool -``` - -### Run the tests -First, edit the keyword in the `scripts/tester.sh` file to select the tests you want to run. Then, run the script -``` -scripts/tester.sh -``` - ## Releases / Versioning This Repository includes a github actions pipeline which builds and releases the wallet framework whenever a Pull Request is submitted or a merge to the main branch happens. When the build and release process is triggered by a pull request the build version has a "pr" suffix. @@ -178,4 +56,4 @@ The build is accessible through the Open Wallet Foundation nuget feed. ## License -[Apache License Version 2.0](https://github.com/hyperledger/aries-cloudagent-python/blob/master/LICENSE) +[Apache License Version 2.0](./LICENSE) diff --git a/docker-compose.test.yaml b/docker-compose.test.yaml deleted file mode 100644 index b9164242..00000000 --- a/docker-compose.test.yaml +++ /dev/null @@ -1,28 +0,0 @@ -version: '3' -services: - indy-pool: - build: - context: . - dockerfile: docker/indy-pool.dockerfile - args: - pool_ip: 10.0.0.10 - networks: - agent_net: - ipv4_address: 10.0.0.10 - - test-agent: - build: - context: . - dockerfile: docker/test-agent.dockerfile - depends_on: - - "indy-pool" - networks: - agent_net: - ipv4_address: 10.0.0.14 - -networks: - agent_net: - driver: bridge - ipam: - config: - - subnet: 10.0.0.0/16 diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index c837bc1e..00000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,56 +0,0 @@ -version: '3' -services: - indy-pool: - build: - context: . - dockerfile: docker/indy-pool.dockerfile - args: - pool_ip: 10.0.0.10 - ports: - - "9701-9709:9701-9709" - networks: - agent_net: - ipv4_address: 10.0.0.10 - - web-agent-1: - build: - context: . - dockerfile: docker/web-agent.dockerfile - environment: - - ASPNETCORE_URLS=http://10.0.0.11:7000 - - ASPNETCORE_ENVIRONMENT=Development - - ENDPOINT_HOST=${HOST1:-http://10.0.0.11:7000} - ports: - - "7000:7000" - depends_on: - - "indy-pool" - links: - - "indy-pool" - networks: - agent_net: - ipv4_address: 10.0.0.11 - - web-agent-2: - build: - context: . - dockerfile: docker/web-agent.dockerfile - environment: - - ASPNETCORE_URLS=http://10.0.0.12:8000 - - ASPNETCORE_ENVIRONMENT=Development - - ENDPOINT_HOST=${HOST2:-http://10.0.0.12:8000} - ports: - - "8000:8000" - depends_on: - - "indy-pool" - links: - - "indy-pool" - networks: - agent_net: - ipv4_address: 10.0.0.12 - -networks: - agent_net: - driver: bridge - ipam: - config: - - subnet: 10.0.0.0/16 \ No newline at end of file diff --git a/docker/commands.txt b/docker/commands.txt deleted file mode 100644 index 469a2313..00000000 --- a/docker/commands.txt +++ /dev/null @@ -1,8 +0,0 @@ -docker build -f indy-pool.dockerfile -t indy_pool . -docker run -itd -p 9701-9709:9701-9709 indy_pool - -Run tests in PowerShell -Get-ChildItem ".\test\" -recurse | where {$_.extension -eq ".csproj"} | % { dotnet test $_.FullName --verbosity normal } - -Run tests in Bash -ls test/**/*.csproj | xargs -L1 dotnet test --verbosity normal \ No newline at end of file diff --git a/docker/docker_pool_genesis.txn b/docker/docker_pool_genesis.txn deleted file mode 100644 index e7a450a5..00000000 --- a/docker/docker_pool_genesis.txn +++ /dev/null @@ -1,4 +0,0 @@ -{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"10.0.0.10","client_port":9702,"node_ip":"10.0.0.10","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"},"metadata":{"from":"Th7MpTaRZVRYnPiabds81Y"},"type":"0"},"txnMetadata":{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"},"ver":"1"} -{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"10.0.0.10","client_port":9704,"node_ip":"10.0.0.10","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"},"metadata":{"from":"EbP4aYNeTHL6q385GuVpRV"},"type":"0"},"txnMetadata":{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"},"ver":"1"} -{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"10.0.0.10","client_port":9706,"node_ip":"10.0.0.10","node_port":9705,"services":["VALIDATOR"]},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"},"metadata":{"from":"4cU41vWW82ArfxJxHkzXPG"},"type":"0"},"txnMetadata":{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"},"ver":"1"} -{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"10.0.0.10","client_port":9708,"node_ip":"10.0.0.10","node_port":9707,"services":["VALIDATOR"]},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"},"metadata":{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"},"type":"0"},"txnMetadata":{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"},"ver":"1"} diff --git a/docker/indy-pool.dockerfile b/docker/indy-pool.dockerfile deleted file mode 100644 index f4a1b657..00000000 --- a/docker/indy-pool.dockerfile +++ /dev/null @@ -1,128 +0,0 @@ -######################################################## -## Creates a pool of nodes that uses -## the payment plugins with plenum. -## -## run the following commands to build and start -## the pool. -## -## localhost -## docker build -f indy-pool.dockerfile -t indy_pool . -## docker run -itd -p 9701-9708:9701-9708 indy_pool -## -## specific IP address -## # replace 192.168.179.90 with your wifi IP address -## docker build --build-arg pool_ip=192.168.179.90 -f ci/indy-pool.dockerfile -t indy_pool . -## docker run -itd -p 192.168.179.90:9701-9708:9701-9708 indy_pool -## -## docker network -## docker network create --subnet 10.0.0.0/8 indy_pool_network -## docker build --build-arg pool_ip=10.0.0.2 -f ci/indy-pool.dockerfile -t indy_pool . -## docker run -d --ip="10.0.0.2" --net=indy_pool_network indy_pool -## -## 'docker ps' will show the container id -## -## To connect to the shell of the container you can use -## the following exec command replacing the -## with the id of the running container. -## -## docker exec -it /bin/bash -## -########################################################FROM ubuntu:16.04 -FROM ubuntu:16.04 - -ARG uid=1000 - -# Install environment -RUN apt-get update -y && apt-get install -y \ - git \ - wget \ - python3.5 \ - python3-pip \ - python-setuptools \ - python3-nacl \ - apt-transport-https \ - ca-certificates \ - supervisor - -RUN pip3 install -U \ - pip==9.0.3 \ - setuptools - -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CE7709D068DB5E88 -ARG indy_stream=stable -RUN echo "deb https://repo.sovrin.org/deb xenial $indy_stream" >> /etc/apt/sources.list - -RUN useradd -ms /bin/bash -u $uid indy - -ARG indy_plenum_ver=1.12.0 -ARG indy_node_ver=1.12.0 -ARG python3_indy_crypto_ver=0.4.5 -ARG indy_crypto_ver=0.4.5 -ARG python3_pyzmq_ver=18.1.0 -ARG sovtoken_ver=1.0.5 -ARG sovtokenfees_ver=1.0.5 - -RUN apt-get update -y && apt-get install -y \ - python3-pyzmq=${python3_pyzmq_ver} \ - indy-plenum=${indy_plenum_ver} \ - indy-node=${indy_node_ver} \ - python3-indy-crypto=${python3_indy_crypto_ver} \ - libindy-crypto=${indy_crypto_ver} \ - sovtoken=${sovtoken_ver} \ - sovtokenfees=${sovtokenfees_ver} \ - vim - -RUN echo "[supervisord]\n\ -logfile = /tmp/supervisord.log\n\ -logfile_maxbytes = 50MB\n\ -logfile_backups=10\n\ -logLevel = error\n\ -pidfile = /tmp/supervisord.pid\n\ -nodaemon = true\n\ -minfds = 1024\n\ -minprocs = 200\n\ -umask = 022\n\ -user = indy\n\ -identifier = supervisor\n\ -directory = /tmp\n\ -nocleanup = true\n\ -childlogdir = /tmp\n\ -strip_ansi = false\n\ -\n\ -[program:node1]\n\ -command=start_indy_node Node1 0.0.0.0 9701 0.0.0.0 9702\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node1.log\n\ -stderr_logfile=/tmp/node1.log\n\ -\n\ -[program:node2]\n\ -command=start_indy_node Node2 0.0.0.0 9703 0.0.0.0 9704\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node2.log\n\ -stderr_logfile=/tmp/node2.log\n\ -\n\ -[program:node3]\n\ -command=start_indy_node Node3 0.0.0.0 9705 0.0.0.0 9706\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node3.log\n\ -stderr_logfile=/tmp/node3.log\n\ -\n\ -[program:node4]\n\ -command=start_indy_node Node4 0.0.0.0 9707 0.0.0.0 9708\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node4.log\n\ -stderr_logfile=/tmp/node4.log\n"\ ->> /etc/supervisord.conf - -USER indy - -RUN awk '{if (index($1, "NETWORK_NAME") != 0) {print("NETWORK_NAME = \"sandbox\"")} else print($0)}' /etc/indy/indy_config.py> /tmp/indy_config.py -RUN mv /tmp/indy_config.py /etc/indy/indy_config.py - -ARG pool_ip=127.0.0.1 - -RUN generate_indy_pool_transactions --nodes 4 --clients 5 --nodeNum 1 2 3 4 --ips="$pool_ip,$pool_ip,$pool_ip,$pool_ip" - -EXPOSE 9701 9702 9703 9704 9705 9706 9707 9708 - -CMD ["/usr/bin/supervisord"] diff --git a/docker/test-agent.dockerfile b/docker/test-agent.dockerfile deleted file mode 100644 index 89c8ce21..00000000 --- a/docker/test-agent.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM streetcred/dotnet-indy:1.14.2 -WORKDIR /app - -COPY . . -RUN dotnet restore "test/Hyperledger.Aries.Tests/Hyperledger.Aries.Tests.csproj" - -COPY docker/docker_pool_genesis.txn test/Hyperledger.Aries.Tests/pool_genesis.txn - -WORKDIR /app/test/Hyperledger.Aries.Tests - -ENTRYPOINT ["dotnet", "test", "--verbosity", "normal"] \ No newline at end of file diff --git a/docker/web-agent.dockerfile b/docker/web-agent.dockerfile deleted file mode 100644 index 448041bd..00000000 --- a/docker/web-agent.dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM streetcred/dotnet-indy:1.14.2 AS base -WORKDIR /app - -FROM streetcred/dotnet-indy:1.14.2 AS build -WORKDIR /src -COPY [".", "."] - -WORKDIR /src/samples/aspnetcore -RUN dotnet restore "WebAgent.csproj" \ - -s "https://api.nuget.org/v3/index.json" - -COPY ["samples/aspnetcore/", "."] -COPY ["docker/docker_pool_genesis.txn", "./pool_genesis.txn"] -RUN dotnet build "WebAgent.csproj" -c Release -o /app - -FROM build AS publish -RUN dotnet publish "WebAgent.csproj" -c Release -o /app - -FROM base AS final -WORKDIR /app -COPY --from=publish /app . - -ENTRYPOINT ["dotnet", "WebAgent.dll"] \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 298ea9e2..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/_static/custom.css b/docs/_static/custom.css deleted file mode 100644 index 90ebe8fe..00000000 --- a/docs/_static/custom.css +++ /dev/null @@ -1,13 +0,0 @@ -.toggle .header { - display: block; - clear: both; - cursor: pointer; -} - -.toggle .header:after { - content: " ▶"; -} - -.toggle .header.open:after { - content: " ▼"; -} \ No newline at end of file diff --git a/docs/_static/images/choose_template.png b/docs/_static/images/choose_template.png deleted file mode 100644 index 8b7c75f9..00000000 Binary files a/docs/_static/images/choose_template.png and /dev/null differ diff --git a/docs/_static/images/configure_agent.png b/docs/_static/images/configure_agent.png deleted file mode 100644 index 2d9daa99..00000000 Binary files a/docs/_static/images/configure_agent.png and /dev/null differ diff --git a/docs/_static/images/target_framework.png b/docs/_static/images/target_framework.png deleted file mode 100644 index 8f385f73..00000000 Binary files a/docs/_static/images/target_framework.png and /dev/null differ diff --git a/docs/_templates/page.html b/docs/_templates/page.html deleted file mode 100644 index 429a7ded..00000000 --- a/docs/_templates/page.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "!page.html" %} - -{% block footer %} - -{% endblock %} \ No newline at end of file diff --git a/docs/aspnetcore.rst b/docs/aspnetcore.rst deleted file mode 100644 index dda8234c..00000000 --- a/docs/aspnetcore.rst +++ /dev/null @@ -1,123 +0,0 @@ -******************************** -Agent services with ASP.NET Core -******************************** - -Installation -============ - -A package with extensions and default implementations for use with ASP.NET Core is available. - -Configure required services -=========================== - -Inside your ``Startup.cs`` fine in ``ConfigureServices(IServiceCollection services)`` use the extension methods to add all dependent services and optionally pass configuration data. - -.. code-block:: csharp - :emphasize-lines: 4 - - public void ConfigureServices(IServiceCollection services) - { - // other configuration - services.AddAgent(); - } - -Configure options manually --------------------------- - -You can customize the wallet and pool configuration options using - -.. code-block:: csharp - - services.AddAgent(config => - { - config.SetPoolOptions(new PoolOptions { GenesisFilename = Path.GetFullPath("pool_genesis.txn") }); - config.SetWalletOptions(new WalletOptions - { - WalletConfiguration = new WalletConfiguration { Id = "MyAgentWallet" }, - WalletCredentials = new WalletCredentials { Key = "SecretWalletEncryptionKeyPhrase" } - }); - }); - -Use options pattern -------------------- - -Alternatively, options be configured using APS.NET Core ``IOptions`` pattern. - -.. code-block:: csharp - - services.Configure(Configuration.GetSection("PoolOptions")); - services.Configure(Configuration.GetSection("WalletOptions")); - -Set any fields you'd like to configure in your ``appsettings.json``. - -.. code-block:: xml - - { - // config options - "WalletOptions": { - "WalletConfiguration": { - "Id": "MyAgentWallet", - "StorageConfiguration": { "Path": "[path to wallet storage]" } - }, - "WalletCredentials": { "Key": "SecretWalletEncryptionKeyPhrase" } - }, - "PoolOptions": { - "GenesisFilename": "[path to genesis file]", - "PoolName": "DefaultPool", - "ProtocolVersion": 2 - } - } - -Initialize agent middleware -=========================== - -In ``Configure(IApplicationBuilder app, IHostingEnvironment env)`` start the default agent middleware - -.. code-block:: csharp - :emphasize-lines: 4 - - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - // Endpoint can be any address you'd like to bind to this middleware - app.UseAgent("http://localhost:5000/agent"); - - // .. other services like app.UseMvc() - } - -The default agent middleware is a simple implementation. You can `create your middleware -`_ and use that instead if you'd like to customize the message handling. - -.. code-block:: csharp - - app.UseAgent("http://localhost:5000/agent"); - -See `AgentMiddleware.cs -`_ for example implementation. - -.. tip:: In ASP.NET Core, the order of middleware registration is important, so you might want to add the agent middleware before any other middlewares, like MVC. - -Calling services from controllers -================================= - -Use dependency injection to get a reference to each service in your controllers. - -.. code-block:: csharp - - public class HomeController : Controller - { - private readonly IConnectionService _connectionService; - private readonly IWalletService _walletService; - private readonly WalletOptions _walletOptions; - - public HomeController( - IConnectionService connectionService, - IWalletService walletService, - IOptions walletOptions) - { - _connectionService = connectionService; - _walletService = walletService; - _walletOptions = walletOptions.Value; - } - - // ... - } diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 5120ab65..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = u'Agent Framework' -copyright = u'2018, Agent Framework' -author = u'Agent Framework and contributors' - -# The short X.Y version -version = u'' -# The full version, including alpha/beta/rc tags -release = u'1.1.0' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ -] - -from recommonmark.parser import CommonMarkParser - -source_parsers = { - '.md': CommonMarkParser, -} - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -source_suffix = ['.rst', '.md'] -# source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = None - -def setup(app): - app.add_stylesheet('custom.css') - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_rtd_theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'AgentFrameworkdoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'AgentFramework.tex', u'Agent Framework Documentation', - u'Agent Framework and contributors', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'agentframework', u'Agent Framework Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'AgentFramework', u'Agent Framework Documentation', - author, 'AgentFramework', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- Options for Epub output ------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = project - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -# -# epub_identifier = '' - -# A unique identification for the text. -# -# epub_uid = '' - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] \ No newline at end of file diff --git a/docs/docker.rst b/docs/docker.rst deleted file mode 100644 index bb5f854b..00000000 --- a/docs/docker.rst +++ /dev/null @@ -1,23 +0,0 @@ -*********************************** -Hosting agents in docker containers -*********************************** - -Hosting agents in docker container is the easiest way to ensure your running environment has all dependencies required by the framework. -We provide images with libindy and dotnet-sdk preinstalled. - -Usage -===== - -.. code-block:: docker - :name: Docker - - FROM streetcred/dotnet-indy:latest - -The images are based on `ubuntu:16.04`. You can check `the docker repo -`_ if you want to build your own image or require specific version of .NET Core or libindy. - -Example build -============= - -Check the `web agent docker file -`_ for an example of building and running ASP.NET Core project inside docker container with libindy support. \ No newline at end of file diff --git a/docs/errors.rst b/docs/errors.rst deleted file mode 100644 index b0a08dca..00000000 --- a/docs/errors.rst +++ /dev/null @@ -1,16 +0,0 @@ -************************** -Common Errors and Problems -************************** - -System.DllNotFoundException -=========================== - -Problem - Runtime exception thrown - -.. code-block:: bash - - System.DllNotFoundException : Unable to load shared library 'libindy' or one of its dependencies. In order to help diagnose loading problems, consider setting the DYLD_PRINT_LIBRARIES environment variable: dlopen(libsovtoken, 1): image not found - -Solution - Missing static library. Check the installation section for guidance on how to add static libraries to your environment. \ No newline at end of file diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst deleted file mode 100644 index d5ff2c7a..00000000 --- a/docs/gettingstarted.rst +++ /dev/null @@ -1,332 +0,0 @@ -********************* -Getting Started Guide -********************* - -Creating a New Project -+++++++++++++++++++++++++++++ - -This getting started guide will show you how to create a custom AspNetCore web application and -use the agent framework to create connections and send basic messages. We are going to start from scratch. All you need to have installed in Visual Studio and the .NET Core SDK. - -Prerequisites -===================================== - -If you haven't already done so, install Visual Studio community and the .NET Core 2.2.300 SDK - - `Install Visual Studio `_ - - `Install .NET Core SDK 2.2 `_ - -You should be running an instance of Windows or MacOS for this particular demo. - ---------------------- - -Create an AspNetCore Project -=============================== - -Open Visual Studio and select new project, then choose Web Application (Model-View-Controller): - -.. image:: _static/images/choose_template.png - :width: 500 - -Select the .NET Core 2.2, then name your project WebAgent. - -.. image:: _static/images/configure_agent.png - :width: 500 - ----------------------- - -Installing the Required Packages -================================ - -Use one of the three methods below to load the AgentFramework.Core packages into your project using nuget. - -**Package Manager CLI:** - -.. code-block:: bash - - Install-Package AgentFramework.Core -Source https://www.myget.org/F/agent-framework/api/v3/index.json -v 4.0.0-preview.662 - -**.NET CLI:** - -.. code-block:: bash - - dotnet add package AgentFramework.Core -s https://www.myget.org/F/agent-framework/api/v3/index.json -v 4.0.0-preview.662 - -NOTE: For these first two CLI options, make sure to install ``AgentFramework.AspNetCore`` and ``AgentFramework.Core.Handlers`` by replacing the package name above with these two names as well. - -**Visual Studio Nuget Package Manager:** - - - click on your new project WebAgent in the side bar - - go to the project tab in your menu, select ``add nuget packages...`` - - click on the dropdown that says nuget.org, and select ``configure sources...`` - - click add, and then name the new source ``Agent Framework Beta`` and paste the url ``https://www.myget.org/F/agent-framework/api/v3/index.json`` into the location field. - - check the ``show pre-release packages`` box on the bottom left - - choose the ``Agent Framework Beta`` source from the dropdown - - select the AgentFramework.AspNetCore package from the list. Make sure it is on a 4.0.0 version - - click add. - - We will also use one other package from Nuget called ``Jdenticon``. Add that from the nuget.org repository list. - ---------------- - -Installing the libindy SDK on your computer -=========================================== - -Windows -~~~~~~~ - -You can download binaries of libindy and all dependencies from the `Sovrin repo -`_. The dependencies are under ``deps`` folder and ``libindy`` under one of streams (rc, master, stable). There are two options to link the DLLs - -- Unzip all files in a directory and add that to your PATH variable (recommended for development) -- Or copy all DLL files in the publish directory (recommended for published deployments) - -More details at the `Indy documentation for setting up Windows environment -`_. - -MacOS -~~~~~ - -Check `Setup Indy SDK build environment for MacOS -`_. - -Copy ``libindy.a`` and ``libindy.dylib`` to the ``/usr/local/lib/`` directory. - -------------------- - -Configuring your own Agent -========================== - -In this section, we'll walk through some sections of the WebAgent sample to understand how the AgentFramework can be used in a running application. - -The WebAgent sample was created using the same steps as listed above. It may help to follow along to the steps below in your own new project. -However, you may want to also open and try to run the fully working WebAgent sample in Visual Studio first to see if all the dependancies are working as they should. -When the project was created, ``Startup.cs`` and ``Program.cs`` files were built using a template. These control how your webserver starts. We will need to -edit them to use the agent framework. - -------------------- - -Startup.cs -~~~~~~~~~~ - -Our first goal is to edit the Startup file. Copy and paste the below code into your ``Startup.cs`` file: - -.. container:: toggle - - .. container:: header - - **Startup.cs (click to show/hide)** - - .. literalinclude:: ../samples/aspnetcore/Startup.cs - :language: csharp - :emphasize-lines: 32-41, 44-45, 64, 72 - :linenos: - -In this file, we congigure and add the Agent Framework to the project. If you are building the project from scratch, -make sure to comment out lines 44-45 until you have created these services. Line 72 specifies how the API to trigger actions should be called. -------------- - -Program.cs -~~~~~~~~~~ - -Next, we will edit the ``Program.cs`` file. Copy and paste this code too: - -.. container:: toggle - - .. container:: header - - **Program.cs** - - .. literalinclude:: ../samples/aspnetcore/Program.cs - :language: csharp - :linenos: - -Once you have finished with this code, take a moment to look over the changes that we've made. - ----------------- - -SimpleWebAgent.cs -~~~~~~~~~~~~~~~~~ -Now create a file name ``SimpleWebAgent.cs`` in the main directory - -This file will inherit from the AgentBase class in the AgentFramework, and it extends the IAgent Interface. -This interface includes only one function named ``TaskProcessAsync(IAgentContext context, MessageContext messageContext)`` -This will process any message that is sent to the agent's endpoint. - -Copy and paste the below code into the file: - -.. container:: toggle - - .. container:: header - - **SimpleWebAgent.cs (Click to show)** - - - .. literalinclude:: ../samples/aspnetcore/SimpleWebAgent.cs - :language: csharp - :linenos: - ------------ - -bundleconfig.json -~~~~~~~~~~~~~~~~~ - -Create a bundleconfig.json file in your project root directory, and paste this json array into to it: - -.. container:: toggle - - .. container:: header - - **bundleconfig.json** - - .. literalinclude:: ../samples/aspnetcore/bundleconfig.json - :language: javascript - :linenos: - -------------------------- - -launchSettings.json -~~~~~~~~~~~~~~~~~~~ - -Edit the ``Property/launchSettings.json`` - -.. container:: toggle - - .. container:: header - - **launchSettings.json** - - .. literalinclude:: ../samples/aspnetcore/Properties/launchSettings.json - :language: javascript - :linenos: - -Finally, to get this program to run we will need to add a couple of utility files. - -First, add a Utils folder. Add these two files to the Utils folder (Open these links in new tabs): - -`NameGenerator.cs `_ -`Extensions.cs `_ - - --------------- - -Click run, you should see your template home page will appear in your web browser at http://localhost:5000. Congratulations! You've successully included the Agent framework into your project. Continue on to see how you might use it in your project. - - -WebAgent Walkthrough -+++++++++++++++++++++ - -We will learn how to create a web agent in this section. If you have created your own agent, you should be able to use that here. You may want to download the `View files `_ and import them into your project to save time on copy/paste: -We're assuming that you are already familiar with the high level concepts of Indy and Sovrin. - -The first thing is to understand about Wallets. Read about wallets here: -**Insert link/paragraphs about wallet infra based on hipe:** `Wallet HIPE `_ - ------------ - -Opening a wallet in Agent Framework -==================================== - -We open a wallet in Agent Framework by provisioning an agent. This process of provisioning -agents will create and configure an agent wallet and initialize the agent configuration. -The framework will generate a random Did and Verkey, unless you specify ``AgentSeed`` -which is used if you need determinism. Length of seed must be 32 characters. - -.. code-block:: csharp - - await _provisioningService.ProvisionAgentAsync( - new ProvisioningConfiguration - { - EndpointUri = "http://localhost:5000", - OwnerName = "My Agent" - }); - -We provision this agent in the ``Startup.cs`` file by building it directly with the AgentBuilder - -.. container:: toggle - - .. container:: header - - **HomeController.cs (Show)** - - .. literalinclude:: ../samples/aspnetcore/Startup.cs - :language: csharp - :emphasize-lines: 32-41 - :linenos: - -You now have a functioning wallet in your agent, ready to store all your secrets. - ------------------ - -The Agent framework abstracts the main workflows of Indy into a state machine. For our agent, we will show how to create and receive invitations with other people. -Although simple, it builds the foundation for all other potential agent communications like credentials and proofs. - -TODO: Basic message and routing info - -Connections -============== - -Every connection is a unique relationship with another agent. The Agent Framework represents this relationship with a ``ConnectionRecord``, this entity describes the pairwise relationship with another party. -The states for this record are: - -- ``Invited`` - initially, when creating invitations to connect, the record will be set to this state. -- ``Negotating`` - set after accepting an invitation and sending a request to connect -- ``Connected`` - set when both parties have acknowledged the connection and have a pairwise record of each others DID's - -For us to send basic messages back and forth, we will first need to establish that protocol. We will walk through how a message is processed in the WebAgent. - -First, we need to define the basic message structure in the Protocols folder. These are all child classes of the AgentMessage class that is in the AgentFramework. - -.. container:: toggle - - .. container:: header - - **AgentMessage.cs (Show)** - - .. literalinclude:: ../src/AgentFramework.Core/Messages/AgentMessage.cs - :language: c# - :linenos: - -The BasicMessage uses the AgentMessage attributes as shown in the class above but adds "content" and "sent_time" attributes as well. This will allow something like text messages to be sent between agents. - -.. container:: toggle - - .. container:: header - - **BasicMessage.cs (Show)** - - .. literalinclude:: ../samples/aspnetcore/Protocols/BasicMessage/BasicMessage.cs - :language: csharp - :emphasize-lines: 16-20 - :linenos: - -When your agent receives a message, it gets put directly into the wallet by the basic message handler. - -.. container:: toggle - - .. container:: header - - **BasicMessageHandler.cs (Show)** - - .. literalinclude:: ../samples/aspnetcore/Protocols/BasicMessage/BasicMessageHandler.cs - :language: csharp - :emphasize-lines: 22-29 - :linenos: - -Then when the view is reloaded, the Controller class takes over. - -This is following the MVC pattern of ASPNetCore. - -Here is the ConnectionsController class that will show a BasicMessage if one is sent or received: - -.. container:: toggle - - .. container:: header - - **ConnectionsController.cs (Show)** - - .. literalinclude:: ../samples/aspnetcore/Controllers/ConnectionsController.cs - :language: csharp - :emphasize-lines: 133, 153 - :linenos: - -Read through the rest of the ConnectionsController class to understand how the Agent Framework can be used to implement the other website features. diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 44baf961..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,42 +0,0 @@ - -******************************************* -Welcome to Agent Framework's documentation! -******************************************* - -AgentFramework is a .NET Core library for building Sovrin interoperable agent services. -It is an abstraction on top of Indy SDK that provides a set of API's for building Indy Agents. -The framework runs on any .NET Standard target, including ASP.NET Core and Xamarin. - -.. toctree:: - :maxdepth: 2 - :caption: Initial Setup - - installation - -.. toctree:: - :maxdepth: 2 - :caption: Framework Model - - quickstart - payments - -.. toctree:: - :maxdepth: 2 - :caption: Deployment Strategies - - xamarin - aspnetcore - docker - -.. toctree:: - :maxdepth: 2 - :caption: Example Agents - - gettingstarted - samples - -.. toctree:: - :maxdepth: 2 - :caption: Common Errors - - errors diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index 74572d97..00000000 --- a/docs/installation.rst +++ /dev/null @@ -1,79 +0,0 @@ - -****************************** -Installation and configuration -****************************** - -Using NuGet -=========== - -To use the agent framework in your project, add the nuget packages. - -If using the package manager: - -.. code-block:: bash - - Install-Package AgentFramework.Core -Source https://www.myget.org/F/agent-framework/api/v3/index.json - -If using the .NET CLI: - -.. code-block:: bash - - dotnet add package AgentFramework.Core -s https://www.myget.org/F/agent-framework/api/v3/index.json - -Available packages: - -- ``AgentFramework.Core`` - core framework package -- ``AgentFramework.AspNetCore`` - simple middleware and service extensions to easily configure and run an agent -- ``AgentFramework.Core.Handlers`` - provides a framework for registering custom message handlers and extending the agent functionality - - -The framework will be moved to nuget.org soon. For the time being, stable and pre-release packages are available at ``https://www.myget.org/F/agent-framework/api/v3/index.json``. -You can add `nuget.config -`_ anywhere in your project path with the myget.org repo. - -.. code-block:: xml - - - - - - - - - -Setting up development environment -================================== - -Agent Framework uses Indy SDK wrapper for .NET which requires platform specific native libraries of libindy to be available in the running environment. -Check the `Indy SDK project page -`_ for details on installing libindy for different platforms or read the brief instructions below. - -Make sure you have `.NET Core SDK -`_ installed for your platform. - -Windows -------- - -You can download binaries of libindy and all dependencies from the `Sovrin repo -`_. The dependencies are under ``deps`` folder and ``libindy`` under one of streams (rc, master, stable). There are two options to link the DLLs - -- Unzip all files in a directory and add that to your PATH variable (recommended for development) -- Or copy all DLL files in the publish directory (recommended for published deployments) - -More details at the `Indy documentation for setting up Windows environment -`_. - -MacOS ------ - -Check `Setup Indy SDK build environment for MacOS -`_. - -Copy ``libindy.a`` and ``libindy.dylib`` to the ``/usr/local/lib/`` directory. - -Linux ------ - -Build instructions for `Ubuntu based distros -`_ and `RHEL based distros -`_. \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 27f573b8..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/docs/payments.rst b/docs/payments.rst deleted file mode 100644 index e4828ca9..00000000 --- a/docs/payments.rst +++ /dev/null @@ -1,54 +0,0 @@ -******** -Payments -******** - -Payments are a core feature of the framework and are implemented as optional module. -Working with payments requires an implementation of the ``IPaymentService`` for that specific payment method. Currently, there's support for Sovrin Token payments. - -Installation -============ - -Packages supporting Sovrin Token payments can be found on nuget.org - -**Package Manager CLI:** - -.. code-block:: bash - - Install-Package AgentFramework.Payments.SovrinToken - -**.NET CLI:** - -.. code-block:: bash - - dotnet add package AgentFramework.Payments.SovrinToken - -Add libsovtoken static library ------------------------------- - - -Configuration -============= - -Records and services -==================== - -Working with payments -===================== - -Create and set default payment address --------------------------------------- - -Check balance at address ------------------------- - -Attaching payments to agent messages ------------------------------------- - -Making payments ---------------- - -Attaching payment receipt to agent messages -------------------------------------------- - -Using libnullpay for development -================================ \ No newline at end of file diff --git a/docs/quickstart.rst b/docs/quickstart.rst deleted file mode 100644 index b1f46fcf..00000000 --- a/docs/quickstart.rst +++ /dev/null @@ -1,270 +0,0 @@ -****************************** -Configuration and provisioning -****************************** - -Services overview -================= - -- ``IProvisioningService`` - used to provision new agents and access the provisioning configuration that contains endpoint data, ownership info, service endpoints, etc. -- ``IConnectionService`` - manage connection records, create and accept invitations -- ``ICredentialService`` - manage credential records, create offer, issue, revoke and store credentials -- ``IProofService`` - send proof requests, provide and verify proofs -- ``IWalletRecordService`` - utility service used to manage custom application records that are stored in the wallet -- ``ISchemaService`` - create and manage schemas and credential definitions - -Dependency injection -==================== - -When using ASP.NET Core, you can use the extension methods to configure the agent. This will add all required dependencies to the service provider. -Additionally, the AgentFramework depends on the Logging extensions. These need to be added as well. - -If using other tool, you will have to add each required service or message handler manually. - -Example if using Autofac - -.. code-block:: csharp - - // .NET Core dependency collection - var services = new ServiceCollection(); - services.AddLogging(); - - // Autofac builder - var builder = new ContainerBuilder(); - - // Register all required services - builder.RegisterAssemblyTypes(typeof(IProvisioningService).Assembly) - .Where(x => x.Namespace.StartsWith("AgentFramework.Core.Runtime", - StringComparison.InvariantCulture)) - .AsImplementedInterfaces() - .SingleInstance(); - - // If using message handler package, you can add all handlers - builder.RegisterAssemblyTypes(typeof(IMessageHandler).Assembly) - .Where(x => x.IsClass && x is IMessageHandler) - .AsSelf() - .SingleInstance(); - - builder.Populate(services); - -Check the `Xamarin Sample -`_ for example registration. - -Provisioning an Agent -===================== - -The process of provisioning agents will create and configure an agent wallet and initialize the agent configuration. -The framework will generate a random Did and Verkey, unless you specify ``AgentSeed`` which is used if you need determinism. -Length of seed must be 32 characters. - -.. code-block:: csharp - - await _provisioningService.ProvisionAgentAsync( - new ProvisioningConfiguration - { - EndpointUri = "http://localhost:5000", - OwnerName = "My Agent" - }); - -Check the `ProvisioningConfiguration.cs -`_ -for full configuration details. You can retrieve the generated details like agent Did and Verkey using - -.. code-block:: csharp - - var provisioning = await _provisioningService.GetProvisioningAsync(wallet); - -Trust Anchor requirement ------------------------- - -If an agent is intended to act as an issuer, i.e. be able to issue credentials, their DID must be registered on the ledger with the `TRUST_ANCHOR` role. -Additionally, when provisioning the agent, set the ``ProvisioningConfiguration.CreateIssuer`` propety to true. If you already have a seed for creating the issuer DID -set the ``ProvisioningConfiguration.IssuerSeed`` to that value. Otherwise, a random DID will be generated. This DID must be added to the ledger as `TRUST_ANCHOR`. - -.. tip:: If you are using the development indy node docker image, use ``000000000000000000000000Steward1`` as issuer seed. This will create a DID that has all required permissions. - -*************** -Agent Workflows -*************** - -Before you begin reading any of the topics below, please familiarize youself with the core principles behind Hyperledger Indy. -We suggest that you go over the `Indy SDK Getting Started Guide -`_. - -Models and states -================= - -The framework abstracts the main workflows of Indy into a state machine model. -The following models and states are defined: - -Connections ------------ - -Represented with a ``ConnectionRecord``, this entity describes the pairwise relationship with another party. -The states for this record are: - -- ``Invited`` - initially, when creating invitations to connect, the record will be set to this state. -- ``Negotating`` - set after accepting an invitation and sending a request to connect -- ``Connected`` - set when both parties have acknowledged the connection and have a pairwise record of each others DID's - -Credentials ------------ - -Represented wih a ``CredentialRecord``, this entity holds a reference to issued credential. -While only the party to whom this credential was issued will have the actual credential in their wallet, both the issuer and the holder will -have a CredentialRecord with the associated status for their reference. Credential states: - -- ``Offered`` - initial state, when an offer is sent to the holder -- ``Requested`` - the holder has sent a credential request to the issuer -- ``Issued`` - the issuer accepted the credential request and issued a credential -- ``Rejected`` - the issuer rejected the credential request -- ``Revoked`` - the issuer revoked a previously issued credential - -Proofs ------- - -Represented with a ``ProofRecord``, this entity references a proof flow between the holder and verifier. The ``ProofRecord`` contains -information about the proof request as well as the disclosed proof by the holder. Proof states: - -- ``Requested`` - initial state when the verifier sends a proof request -- ``Accepted`` - the holder has provided a proof -- ``Rejected`` - the holder rejected providing proof for the request - -Schemas and definitions -======================= - -Before an issuer can create credentials, they need to register a credential definition for them on the ledger. -Credential definition requires a schema, which can also be registered by the same issuer or it can already be -present on the ledger. - -.. code-block:: csharp - - // creates new schema and registers the schema on the ledger - var schemaId = await _schemaService.CreateSchemaAsync( - _pool, _wallet, "My-Schema", "1.0", new[] { "FirstName", "LastName", "Email" }); - - // to lookup an existing schema on the ledger - var schemaJson = await _schemaService.LookupSchemaAsync(_pool, schemaId); - -Once a ``schemaId`` has been established, an issuer can send their credential definition on the ledger. - -.. code-block:: csharp - - var definitionId = await _schemaService.CreateCredentialDefinitionAsync(_pool, _wallet, - schemaId, supportsRevocation: true, maxCredentialCount: 100); - -The above code will create ``SchemaRecord`` and ``DefinitionRecord`` in the issuer wallet that can be looked up using the -``ISchemaService``. - -.. warning:: Creating schemas and definition requires an issuer. See the `Trust Anchor requirement`_ above. - -To retrieve all schemas or definitions registered with this agent, use: - -.. code-block:: csharp - - var schemas = await _schemaService.ListSchemasAsync(_wallet); - var definitions = await _schemaService.ListCredentialDefinitionsAsync(_wallet); - - // To get a single record - var definition = await _schemaService.GetCredentialDefinitionAsync(wallet, definitionId); - -Establishing secure connection -============================== - -Before two parties can exchange agent messages, a secure connection must be established between them. The agent connection workflow defines this handshake process by exchanging a connection request/response message. - -Sending invitations -------------------- - -Connection invitations are exchanged over a previously established trusted protocol such as email, QR code, deep link, etc. When Alice wants to establish a connection to Bob, she can create an invitation: - -.. code-block:: csharp - - // Alice creates an invitation - var invitation = await connectionService.CreateInvitationAsync(aliceWallet); - -She sends this invitation to Bob using the above described methods. - -Negotating connection ---------------------- - -Once Bob received the invitation from Alice, they can accept that invitation and initiate the negotiation process - -.. code-block:: csharp - - // Bob accepts invitation and sends a message request - await connectionService.AcceptInvitationAsync(bobWallet, invitation); - -If you are using the default message handlers, no other step in needed - connection between Alice and Bob has been established. Use ``IConnectionService.ListAsync`` to fetch the connection records. -Established connections will have the ``State`` property set to ``Connected``. - -.. tip:: If you decide to use custom handlers and want more control over the negotiation process, the connection service provides methods to work with the connections message flows, such as processing and accepting requests/responses. - A full step by step code is available in the `unit tests project - `_ in ``EstablishConnectionAsync``. - -Credential issuance -=================== - -An issuer may use the ``ICredentialService`` to issue new credentials. A credential issuance starts with a credential offer. - -.. code-block:: csharp - - var offerConfig = new OfferConfiguration() - { - // the id of the connection record to which this offer will be sent - ConnectionId = connectionId, - CredentialDefinitionId = definitionId - }; - - // Send an offer to the holder using the established connection channel - var credentialRecordId = await credentialService.SendOfferAsync(issuerWallet, offerConfig); - -When credential offer is sent, new ``CredentialRecord`` will be created and it's state set to ``Offered``. You can list all credential records using - -.. code-block:: csharp - - var credentials = await credentialService.ListAsync(); - -Issuing credential ------------------- - -.. code-block:: csharp - - var values = new Dictionary - { - {"FirstName", "Jane"}, - {"LastName", "Doe"}, - {"Email", "no@spam"} - }; - - // Issuer accepts the credential requests and issues a credential - await credentialService.IssueCredentialAsync(pool, issuerWallet, credentialRecordId, values); - -An issuer can issue a credential only if the credential record state is ``Requested``. This means that the holder has accepted the offer -and sent back a credential request message. - -Storing issued credential -------------------------- - -If using the default handlers, once a credential has been issued and received by the holder's agent, it will be automatically stored and available in the wallet. - -Revocation ----------- - -If the credential definition supports revocation (can only be set when creating the definition), an issuer may decide to revoke a credential. - -.. code-block:: csharp - - // Revokes a credential, updates the tails file and sends the delta to the ledger - await credentialService.RevokeCredentialAsync(pool, wallet, credentialRecordId) - -Proof verification -================== - -Proof requests --------------- - -Preparing proof ---------------- - -Verification ------------- \ No newline at end of file diff --git a/docs/samples.rst b/docs/samples.rst deleted file mode 100644 index 9356b9ec..00000000 --- a/docs/samples.rst +++ /dev/null @@ -1,71 +0,0 @@ -******* -Samples -******* - -ASP.NET Core Agents -=================== - -A sample agent running in ASP.NET Core that runs the default agent middleware can be found in `samples/aspnetcore -`_. This agent is also used in the Docker sample. - -.. code-block:: bash - - dotnet run --project samples/aspnetcore/WebAgent.csproj - -Running multiple instances --------------------------- - -To run multiple agent instances that can communicate, you can specify the binding address and port by setting the ``ASPNETCORE_URLS`` environment variable - -.. code-block:: bash - - # Unix/Mac: - ASPNETCORE_URLS="http://localhost:5001" dotnet run --no-launch-profile --project samples/aspnetcore/WebAgent.csproj - - # Windows PowerShell: - $env:ASPNETCORE_URLS="http://localhost:5001" ; dotnet run --no-launch-profile --project samples/aspnetcore/WebAgent.csproj - - # Windows CMD (note: no quotes): - SET ASPNETCORE_URLS=http://localhost:5001 && dotnet run --no-launch-profile --project samples/aspnetcore/WebAgent.csproj - -.. note:: The sample web agent doesn't use any functionality that requires a local indy node, but if you'd like to - extend the sample and test interaction with the ledger, you can run a local node using the instructions below. - -Run a local Indy node with Docker ---------------------------------- - -The repo contains a docker image that can be used to run a local pool with 4 nodes. - -.. code-block:: bash - - docker build -f docker/indy-pool.dockerfile -t indy_pool . - docker run -itd -p 9701-9709:9701-9709 indy_pool - -Mobile Agent with Xamarin Forms -=============================== - - - -Docker container example -======================== - -Running the example -------------------- - -At the root of the repo run: - -.. code-block:: bash - - docker-compose up - -This will create an agent network with a pool and two identical agents able to communicate with each other in the network. -Navigate to http://localhost:7000/ and http://localhost:8000/ to create and accept connection invitations between the different agents. - -Running the unit tests ----------------------- - -.. code-block:: bash - - docker-compose -f docker-compose.test.yaml up --build --remove-orphans --abort-on-container-exit --exit-code-from test-agent - -Note: You may need to cleanup previous docker network created using `docker network prune` diff --git a/docs/xamarin.rst b/docs/xamarin.rst deleted file mode 100644 index cc7cd885..00000000 --- a/docs/xamarin.rst +++ /dev/null @@ -1,204 +0,0 @@ -************************** -Mobile Agents with Xamarin -************************** - -Using Indy with Xamarin -======================= - -When working with Xamarin, we can fully leverage the offical `Indy wrapper for dotnet`_, since the package is fully compatible with Xamarin runtime. The wrapper uses ``DllImport`` to invoke the native Indy library which exposes all functionality as C callable functions. -In order to make the library work in Xamarin, we need to make `libindy` available for Android and iOS, which requires bundling static libraries of libindy and it's dependencies built for each platform. - -.. _`Indy wrapper for dotnet`: https://github.com/hyperledger/indy-sdk/tree/master/wrappers/dotnet - -Instructions for Android -======================== - -To setup Indy on Android you need to add the native libindy references and dependencies. The process is described in detail at the official Xamarin documentation `Using Native Libraries with Xamarin.Android`_. - -.. _`Using Native Libraries with Xamarin.Android`: https://docs.microsoft.com/en-us/xamarin/android/platform/native-libraries - -Below are a few additional things that are not covered by the documentation that are Indy specific. - -Download static libraries -------------------------- - -- Sovrin repo - https://repo.sovrin.org/android/libindy/ - -For Android the entire library and its dependencies are compiled into a single shared object (libindy.so). In order for ``libindy.so`` to be executable we must also include ``libc++_shared.so``. - -.. note:: You can find ``libc++_shared.so`` in your ``android-ndk`` installation directory under ``\sources\cxx-stl\llvm-libc++\libs``. - -.. note:: libindy versions < 1.12.0 were compiled using GCC and require ``libgnustl_shared.so`` instead of ``libc++_shared.so```. This is available in Android NDK versions < 18. - -Depending on the target abi(s) for the resulting app, not all of the artifacts need to be included, for ease of use below we document including all abi(s). - -Setup native references ----------------------------- - -In Visual Studio (for Windows or Mac) create new Xamarin Android project. If you want to use Xamarin Forms, the instructions are the same. Apply the changes to your Android project in Xamarin Forms. - -The required files can be added via your IDE by clicking Add-Item and setting the build action to ``AndroidNativeLibrary``. However when dealing with multiple ABI targets it is easier to manually add the references via the android projects .csproj. Note - if the path contains the abi i.e `..\x86\library.so` then the build process automatically infers the target ABI. - -If you are adding all the target ABI's to you android project add the following snippet to your .csproj. - -.. code-block:: xml - - - - - - - - - - - - - - -.. note:: Paths listed above will vary project to project. - -Load runtime dependencies -------------------------- - -Load these dependencies at runtime. To do this add the following to your MainActivity.cs - -.. code-block:: csharp - - JavaSystem.LoadLibrary("c++_shared"); - JavaSystem.LoadLibrary("indy"); - -Setup Android permissions -------------------------- - -In order to use most of libindy's functionality, the following permissions must be granted to your app, you can do this by adjusting your AndroidManifest.xml, located under properties in your project. - -.. code-block:: xml - - - - - -If you are running your android app at API level 23 and above, these permissions also must be requested at runtime, in order to do this add the following to your MainActivity.cs - -.. code-block:: csharp - - if (Build.VERSION.SdkInt >= BuildVersionCodes.M) - { - RequestPermissions(new[] { Manifest.Permission.ReadExternalStorage }, 10); - RequestPermissions(new[] { Manifest.Permission.WriteExternalStorage }, 10); - RequestPermissions(new[] { Manifest.Permission.Internet }, 10); - } - -Instructions for iOS -==================== - -To setup Indy on iOS you need to add the native libindy references and dependencies. -The process is described in detail at the official Xamarin documentation `Native References in iOS, Mac, and Bindings Projects -`_. - -Below are a few additional things that are not covered by the documentation that are Indy specific. - -Download static libraries -------------------------- - -In order to enable the Indy SDK package to recognize the `DllImport` calls to the native static libraries, we need to include them in our solution. - -These includes the following static libraries: - -- libindy.a -- libssl.a -- libsodium.a -- libcrypto.a -- libzmq.a - -Pre-built libraries -``````````````````` - -Can be found in the `iOS sample project -`_. - -Build your own libs -``````````````````` - -The Indy team doesn't provide static libraries for all of the dependencies for iOS. -Here are some helpful instructions on building the dependencies for iOS should you decide to build your own. - -- `Open SSL for iOS`_ -- `Build ZeroMQ library`_ -- `libsodium script of iOS`_ - -.. _`Open SSL for iOS`: https://github.com/x2on/OpenSSL-for-iPhone - -.. _`Build ZeroMQ library`: https://www.ics.com/blog/lets-build-zeromq-library - -.. _`libsodium script of iOS`: https://github.com/jedisct1/libsodium/blob/master/dist-build/ios.sh - -The above links should help you build the 4 static libraries that libindy depends on. To build libindy for iOS, check out the offical Indy SDK repo or [download the library from the Sovrin repo](https://repo.sovrin.org/ios/libindy/). - -Setup native references ------------------------ - -In Visual Studio (for Windows or Mac) create new Xamarin iOS project. If you want to use Xamarin Forms, the instructions are the same. Apply the changes to your iOS project in Xamarin Forms. - -Add each library as native reference, either by right clicking the project and Add Native Reference, or add them directly in the project file. - -.. note:: Make sure libraries are set to ``Static`` in the properties window and ``Is C++`` is selected for ``libzmq.a`` only. - -The final project file should look like this (paths will vary per project): - -.. code-block:: xml - - - - Static - - - Static - - - Static - - - Static - True - - - Static - - - -Update MTouch arguments ------------------------ - -In your project options under `iOS Build` add the following to `Additional mtouch arguments` - -.. code-block:: bash - - -gcc_flags -dead_strip -v - -If you prefer to add them directly in the project file, add the following line: - -.. code-block:: xml - - -gcc_flags -dead_strip -v - -.. warning:: This step is mandatory, otherwise you won't be able to build the project. - It prevents linking unused symbols in the static libraries. Make sure you add these arguments for all configurations. See `example project file - `_. - -Install NuGet packages ----------------------- - -Install the Nuget packages for Indy SDK and/or Agent Framework and build your solution. Everything should work and run just fine. - -.. code-block:: bash - - dotnet add package AgentFramework.Core --source https://www.myget.org/F/agent-framework/api/v3/index.json - ----- - -If you run into any errors or need help setting up, please open an issue in this repo. - -Finally, check the `Xamarin Sample -`_ we have included for a fully configured project. diff --git a/legacy/Directory.Build.props b/legacy/Directory.Build.props new file mode 100644 index 00000000..df8c71ab --- /dev/null +++ b/legacy/Directory.Build.props @@ -0,0 +1,49 @@ + + + $(NoWarn);CS0612;CS0618;NU1902 + 0 + + + + <_LegacyRefs Include="@(ProjectReference)" Condition="$([System.String]::Copy('%(ProjectReference.Identity)').ToLowerInvariant()).Contains('/legacy/') or + $([System.String]::Copy('%(ProjectReference.Identity)').ToLowerInvariant()).Contains('\legacy\')" /> + + + + + 2.2.0 + 2.2.0 + 2.2.2 + 3.0.0 + 3.1.5 + 3.1.5 + 3.1.5 + 16.6.1 + 4.4.1 + 4.7.2 + 6.0.0 + 1.12.0 + 5.10.3 + 9.2.0 + 9.2.0 + 2.8.2 + 2.0.1 + 0.4.2-alpha + 8.0.1 + 8.0.2 + 4.0.0 + 4.14.5 + 2.0.2 + 13.0.1 + 4.7.2 + 8.5.0 + 5.1.2 + 5.5.1 + 5.1.2 + 5.5.1 + 5.5.1 + 5.5.1 + 2.4.2 + 2.7.0 + + diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/.editorconfig b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/.editorconfig similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/.editorconfig rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/.editorconfig diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/AssemblyAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/AssemblyAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/AssemblyAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/AssemblyAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseApiRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseApiRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseApiRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseApiRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Base/BaseResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/BasicMessaging/SendMessage/SendMessageResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/AcceptInvitation/AcceptInvitationResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/CreateInvitation/CreateInvitationResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/DeleteConnection/DeleteConnectionResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnection/GetConnectionResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/GetConnections/GetConnectionsResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/ReceiveInvitation/ReceiveInvitationResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/SendPing/SendPingResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/_._ b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Connection/_._ diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredential/GetCredentialResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/GetCredentials/GetCredentialsResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Credential/RemoveCredential/RemoveCredentialResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Infrastructure/InternalsVisibleToClientAndServer.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Infrastructure/InternalsVisibleToClientAndServer.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Infrastructure/InternalsVisibleToClientAndServer.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Infrastructure/InternalsVisibleToClientAndServer.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Introduction/_._ b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Introduction/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Introduction/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Introduction/_._ diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/IssueCredential/OfferCredential/OfferCredentialResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Ledger/_._ b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Ledger/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Ledger/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Ledger/_._ diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/AcceptProofRequest/AcceptProofRequestResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/CreateProof/CreateProofRequestResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProof/GetProofResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/PresentProof/GetProofs/GetProofsResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Revocation/_._ b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Revocation/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Revocation/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Revocation/_._ diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/CreateSchema/CreateSchemaResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchema/GetSchemaResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Schema/GetSchemas/GetSchemasResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/TrustPing/_._ b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/TrustPing/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/TrustPing/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/TrustPing/_._ diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/FeatureAnnotations.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/FeatureAnnotations.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/FeatureAnnotations.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/FeatureAnnotations.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/GetWallet/GetWalletResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequest.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequest.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequest.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequest.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequestValidator.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequestValidator.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequestValidator.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletRequestValidator.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletResponse.cs b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletResponse.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletResponse.cs rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Features/Wallet/ResetWallet/ResetWalletResponse.cs diff --git a/src/Hyperledger.Aries.AspNetCore.Contracts/Hyperledger.Aries.AspNetCore.Contracts.csproj b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Hyperledger.Aries.AspNetCore.Contracts.csproj similarity index 89% rename from src/Hyperledger.Aries.AspNetCore.Contracts/Hyperledger.Aries.AspNetCore.Contracts.csproj rename to legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Hyperledger.Aries.AspNetCore.Contracts.csproj index 9ce251b2..d0e4ddd2 100644 --- a/src/Hyperledger.Aries.AspNetCore.Contracts/Hyperledger.Aries.AspNetCore.Contracts.csproj +++ b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/Hyperledger.Aries.AspNetCore.Contracts.csproj @@ -28,4 +28,8 @@ + + + + diff --git a/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/buildTransitive/Legacy.Deprecated.targets b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/buildTransitive/Legacy.Deprecated.targets new file mode 100644 index 00000000..76510c8b --- /dev/null +++ b/legacy/src/Hyperledger.Aries.AspNetCore.Contracts/buildTransitive/Legacy.Deprecated.targets @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Hyperledger.Aries.AspNetCore/.editorconfig b/legacy/src/Hyperledger.Aries.AspNetCore/.editorconfig similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/.editorconfig rename to legacy/src/Hyperledger.Aries.AspNetCore/.editorconfig diff --git a/src/Hyperledger.Aries.AspNetCore/AgentMiddleware.cs b/legacy/src/Hyperledger.Aries.AspNetCore/AgentMiddleware.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/AgentMiddleware.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/AgentMiddleware.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Extensions/ApplicationBuilderExtensions.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Extensions/ApplicationBuilderExtensions.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Extensions/ApplicationBuilderExtensions.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Extensions/ApplicationBuilderExtensions.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Extensions/AriesOpenApiOptions.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Extensions/AriesOpenApiOptions.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Extensions/AriesOpenApiOptions.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Extensions/AriesOpenApiOptions.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Extensions/MvcBuilderExtensions.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Extensions/MvcBuilderExtensions.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Extensions/MvcBuilderExtensions.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Extensions/MvcBuilderExtensions.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Base/BaseEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseError.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseError.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Base/BaseError.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseError.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseException.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseException.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Base/BaseException.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Base/BaseException.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/BasicMessage/SendMessage/SendMessageHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/AcceptInvitation/AcceptInvitationHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/CreateInvitation/CreateInvitationHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/DeleteConnection/DeleteConnectionHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnection/GetConnectionHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/GetConnections/GetConnectionsHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/ReceiveInvitation/ReceiveInvitationHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Connection/SendPing/SendPingHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredential/GetCredentialHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/GetCredentials/GetCredentialsHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Credential/RemoveCredential/RemoveCredentialHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/CreateCredentialDefinition/CreateCredentialDefinitionHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinition/GetCredentialDefinitionHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/CredentialDefinition/GetCredentialDefinitions/GetCredentialDefinitionsHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Introduction/_._ b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Introduction/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Introduction/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Introduction/_._ diff --git a/src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/IssueCredential/OfferCredential/OfferCredentialHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Ledger/_._ b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Ledger/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Ledger/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Ledger/_._ diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/AcceptProofRequest/AcceptProofRequestHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestsHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestsHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestsHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/CreateProofRequest/CreateProofRequestsHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetCredentialsForProof/GetCredentialsForProofHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProof/GetProofHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/PresentProof/GetProofs/GetProofsHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Revocation/_._ b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Revocation/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Revocation/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Revocation/_._ diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/CreateSchema/CreateSchemaHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchema/GetSchemaHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Schema/GetSchemas/GetSchemasHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/TrustPing/_._ b/legacy/src/Hyperledger.Aries.AspNetCore/Features/TrustPing/_._ similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/TrustPing/_._ rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/TrustPing/_._ diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/GetWallet/GetWalletHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletEndpoint.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletEndpoint.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletEndpoint.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletHandler.cs b/legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletHandler.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletHandler.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/Features/Wallet/ResetWallet/ResetWalletHandler.cs diff --git a/src/Hyperledger.Aries.AspNetCore/Hyperledger.Aries.AspNetCore.csproj b/legacy/src/Hyperledger.Aries.AspNetCore/Hyperledger.Aries.AspNetCore.csproj similarity index 92% rename from src/Hyperledger.Aries.AspNetCore/Hyperledger.Aries.AspNetCore.csproj rename to legacy/src/Hyperledger.Aries.AspNetCore/Hyperledger.Aries.AspNetCore.csproj index 7c95f345..930066b2 100644 --- a/src/Hyperledger.Aries.AspNetCore/Hyperledger.Aries.AspNetCore.csproj +++ b/legacy/src/Hyperledger.Aries.AspNetCore/Hyperledger.Aries.AspNetCore.csproj @@ -28,4 +28,8 @@ + + + + diff --git a/src/Hyperledger.Aries.AspNetCore/TailsMiddleware.cs b/legacy/src/Hyperledger.Aries.AspNetCore/TailsMiddleware.cs similarity index 100% rename from src/Hyperledger.Aries.AspNetCore/TailsMiddleware.cs rename to legacy/src/Hyperledger.Aries.AspNetCore/TailsMiddleware.cs diff --git a/legacy/src/Hyperledger.Aries.AspNetCore/buildTransitive/Legacy.Deprecated.targets b/legacy/src/Hyperledger.Aries.AspNetCore/buildTransitive/Legacy.Deprecated.targets new file mode 100644 index 00000000..76510c8b --- /dev/null +++ b/legacy/src/Hyperledger.Aries.AspNetCore/buildTransitive/Legacy.Deprecated.targets @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/AgentBuilderExtensions.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/AgentBuilderExtensions.cs similarity index 100% rename from src/Hyperledger.Aries.Payments.SovrinToken/AgentBuilderExtensions.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/AgentBuilderExtensions.cs diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/AnyAgentMessage.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/AnyAgentMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Payments.SovrinToken/AnyAgentMessage.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/AnyAgentMessage.cs diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/GlobalSuppressions.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/GlobalSuppressions.cs similarity index 98% rename from src/Hyperledger.Aries.Payments.SovrinToken/GlobalSuppressions.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/GlobalSuppressions.cs index df79da48..cf23f1d3 100644 --- a/src/Hyperledger.Aries.Payments.SovrinToken/GlobalSuppressions.cs +++ b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/GlobalSuppressions.cs @@ -1,9 +1,9 @@ - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0165:Asynchronous methods should return a Task instead of void", Justification = "", Scope = "member", Target = "~M:Hyperledger.Aries.Payments.SovrinToken.SovrinTokenConfigurationService.CreateDefaultPaymentAddress")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Name must match C callable method", Scope = "member", Target = "~M:Hyperledger.Aries.Payments.SovrinToken.TokenConfiguration.sovtoken_init")] - + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0165:Asynchronous methods should return a Task instead of void", Justification = "", Scope = "member", Target = "~M:Hyperledger.Aries.Payments.SovrinToken.SovrinTokenConfigurationService.CreateDefaultPaymentAddress")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Name must match C callable method", Scope = "member", Target = "~M:Hyperledger.Aries.Payments.SovrinToken.TokenConfiguration.sovtoken_init")] + diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/Hyperledger.Aries.Payments.SovrinToken.csproj b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/Hyperledger.Aries.Payments.SovrinToken.csproj similarity index 97% rename from src/Hyperledger.Aries.Payments.SovrinToken/Hyperledger.Aries.Payments.SovrinToken.csproj rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/Hyperledger.Aries.Payments.SovrinToken.csproj index 677184d9..a6857eb8 100644 --- a/src/Hyperledger.Aries.Payments.SovrinToken/Hyperledger.Aries.Payments.SovrinToken.csproj +++ b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/Hyperledger.Aries.Payments.SovrinToken.csproj @@ -1,10 +1,10 @@ - - - false - bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Payments.SovrinToken.xml - - - - - - + + + false + bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Payments.SovrinToken.xml + + + + + + diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/PaymentUtils.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/PaymentUtils.cs similarity index 100% rename from src/Hyperledger.Aries.Payments.SovrinToken/PaymentUtils.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/PaymentUtils.cs diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/PaymentsAgentMiddleware.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/PaymentsAgentMiddleware.cs similarity index 100% rename from src/Hyperledger.Aries.Payments.SovrinToken/PaymentsAgentMiddleware.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/PaymentsAgentMiddleware.cs diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/SovrinPaymentService.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/SovrinPaymentService.cs similarity index 100% rename from src/Hyperledger.Aries.Payments.SovrinToken/SovrinPaymentService.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/SovrinPaymentService.cs diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/SovrinTokenConfigurationService.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/SovrinTokenConfigurationService.cs similarity index 100% rename from src/Hyperledger.Aries.Payments.SovrinToken/SovrinTokenConfigurationService.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/SovrinTokenConfigurationService.cs diff --git a/src/Hyperledger.Aries.Payments.SovrinToken/TokenConfiguration.cs b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/TokenConfiguration.cs similarity index 97% rename from src/Hyperledger.Aries.Payments.SovrinToken/TokenConfiguration.cs rename to legacy/src/Hyperledger.Aries.Payments.SovrinToken/TokenConfiguration.cs index 3ade70ea..29ce7450 100644 --- a/src/Hyperledger.Aries.Payments.SovrinToken/TokenConfiguration.cs +++ b/legacy/src/Hyperledger.Aries.Payments.SovrinToken/TokenConfiguration.cs @@ -1,33 +1,33 @@ using System.Runtime.InteropServices; -using System.Threading.Tasks; - -namespace Hyperledger.Aries.Payments.SovrinToken -{ - /// - /// Token Configuration - /// - public static class TokenConfiguration - { - /// - /// Method Name - /// - public const string MethodName = "sov"; - - /// - /// Initializes the internal static library - /// - /// +using System.Threading.Tasks; + +namespace Hyperledger.Aries.Payments.SovrinToken +{ + /// + /// Token Configuration + /// + public static class TokenConfiguration + { + /// + /// Method Name + /// + public const string MethodName = "sov"; + + /// + /// Initializes the internal static library + /// + /// public static Task InitializeAsync() => Task.Run(async () => { await Task.Yield(); - sovtoken_init(); - }); - -#if __IOS__ - [DllImport("__Internal", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] -#else - [DllImport("sovtoken", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] -#endif - internal static extern void sovtoken_init(); - } -} + sovtoken_init(); + }); + +#if __IOS__ + [DllImport("__Internal", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] +#else + [DllImport("sovtoken", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] +#endif + internal static extern void sovtoken_init(); + } +} diff --git a/src/Hyperledger.Aries.Routing.Edge/AriesFrameworkBuilderExtensions.cs b/legacy/src/Hyperledger.Aries.Routing.Edge/AriesFrameworkBuilderExtensions.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Edge/AriesFrameworkBuilderExtensions.cs rename to legacy/src/Hyperledger.Aries.Routing.Edge/AriesFrameworkBuilderExtensions.cs diff --git a/src/Hyperledger.Aries.Routing.Edge/EdgeClientService.Backup.cs b/legacy/src/Hyperledger.Aries.Routing.Edge/EdgeClientService.Backup.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Edge/EdgeClientService.Backup.cs rename to legacy/src/Hyperledger.Aries.Routing.Edge/EdgeClientService.Backup.cs diff --git a/src/Hyperledger.Aries.Routing.Edge/EdgeClientService.cs b/legacy/src/Hyperledger.Aries.Routing.Edge/EdgeClientService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Edge/EdgeClientService.cs rename to legacy/src/Hyperledger.Aries.Routing.Edge/EdgeClientService.cs diff --git a/src/Hyperledger.Aries.Routing.Edge/EdgeConnectionService.cs b/legacy/src/Hyperledger.Aries.Routing.Edge/EdgeConnectionService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Edge/EdgeConnectionService.cs rename to legacy/src/Hyperledger.Aries.Routing.Edge/EdgeConnectionService.cs diff --git a/src/Hyperledger.Aries.Routing.Edge/EdgeProvisioningService.cs b/legacy/src/Hyperledger.Aries.Routing.Edge/EdgeProvisioningService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Edge/EdgeProvisioningService.cs rename to legacy/src/Hyperledger.Aries.Routing.Edge/EdgeProvisioningService.cs diff --git a/src/Hyperledger.Aries.Routing.Edge/Hyperledger.Aries.Routing.Edge.csproj b/legacy/src/Hyperledger.Aries.Routing.Edge/Hyperledger.Aries.Routing.Edge.csproj similarity index 85% rename from src/Hyperledger.Aries.Routing.Edge/Hyperledger.Aries.Routing.Edge.csproj rename to legacy/src/Hyperledger.Aries.Routing.Edge/Hyperledger.Aries.Routing.Edge.csproj index 41c63b3f..dca7c2e1 100644 --- a/src/Hyperledger.Aries.Routing.Edge/Hyperledger.Aries.Routing.Edge.csproj +++ b/legacy/src/Hyperledger.Aries.Routing.Edge/Hyperledger.Aries.Routing.Edge.csproj @@ -1,16 +1,18 @@ - - - WalletFramework.Routing.Edge - bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Routing.Edge.xml - - - - - - - - - EdgeClientService.cs - - - + + + WalletFramework.Routing.Edge + bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Routing.Edge.xml + false + netstandard2.1 + + + + + + + + + EdgeClientService.cs + + + diff --git a/src/Hyperledger.Aries.Routing.Edge/IEdgeClientService.cs b/legacy/src/Hyperledger.Aries.Routing.Edge/IEdgeClientService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Edge/IEdgeClientService.cs rename to legacy/src/Hyperledger.Aries.Routing.Edge/IEdgeClientService.cs diff --git a/src/Hyperledger.Aries.Routing.Edge/IEdgeProvisioningService.cs b/legacy/src/Hyperledger.Aries.Routing.Edge/IEdgeProvisioningService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Edge/IEdgeProvisioningService.cs rename to legacy/src/Hyperledger.Aries.Routing.Edge/IEdgeProvisioningService.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/AriesFrameworkBuilderExtensions.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/AriesFrameworkBuilderExtensions.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/AriesFrameworkBuilderExtensions.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/AriesFrameworkBuilderExtensions.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/DefaultRoutingStore.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/DefaultRoutingStore.cs similarity index 99% rename from src/Hyperledger.Aries.Routing.Mediator/DefaultRoutingStore.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/DefaultRoutingStore.cs index ee707837..d10766a9 100644 --- a/src/Hyperledger.Aries.Routing.Mediator/DefaultRoutingStore.cs +++ b/legacy/src/Hyperledger.Aries.Routing.Mediator/DefaultRoutingStore.cs @@ -21,11 +21,11 @@ public DefaultRoutingStore( public async Task AddRouteAsync(string destinationRoute, string inboxId) { var agentContext = await agentProvider.GetContextAsync(); - var routeRecord = new RouteRecord - { - Id = destinationRoute, - InboxId = inboxId - }; + var routeRecord = new RouteRecord + { + Id = destinationRoute, + InboxId = inboxId + }; await recordService.AddAsync(agentContext.Wallet, routeRecord); } diff --git a/src/Hyperledger.Aries.Routing.Mediator/Handlers/MediatorForwardHandler.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/MediatorForwardHandler.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Handlers/MediatorForwardHandler.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/MediatorForwardHandler.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Handlers/RetrieveBackupHandler.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/RetrieveBackupHandler.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Handlers/RetrieveBackupHandler.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/RetrieveBackupHandler.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Handlers/RoutingInboxHandler.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/RoutingInboxHandler.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Handlers/RoutingInboxHandler.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/RoutingInboxHandler.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Handlers/StoreBackupHandler.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/StoreBackupHandler.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Handlers/StoreBackupHandler.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Handlers/StoreBackupHandler.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Hyperledger.Aries.Routing.Mediator.csproj b/legacy/src/Hyperledger.Aries.Routing.Mediator/Hyperledger.Aries.Routing.Mediator.csproj similarity index 79% rename from src/Hyperledger.Aries.Routing.Mediator/Hyperledger.Aries.Routing.Mediator.csproj rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Hyperledger.Aries.Routing.Mediator.csproj index 4c3a6bfe..b95858cf 100644 --- a/src/Hyperledger.Aries.Routing.Mediator/Hyperledger.Aries.Routing.Mediator.csproj +++ b/legacy/src/Hyperledger.Aries.Routing.Mediator/Hyperledger.Aries.Routing.Mediator.csproj @@ -1,16 +1,20 @@ - - - - WalletFramework.Routing.Mediator - bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Routing.Mediator.xml - - - - - - - - - - - + + + + WalletFramework.Routing.Mediator + bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Routing.Mediator.xml + + + + + + + + + + + + + + + diff --git a/src/Hyperledger.Aries.Routing.Mediator/IRoutingStore.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/IRoutingStore.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/IRoutingStore.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/IRoutingStore.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/MediatorAgent.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/MediatorAgent.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/MediatorAgent.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/MediatorAgent.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/MediatorDiscoveryMiddleware.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/MediatorDiscoveryMiddleware.cs similarity index 97% rename from src/Hyperledger.Aries.Routing.Mediator/MediatorDiscoveryMiddleware.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/MediatorDiscoveryMiddleware.cs index a1b8d5a5..d22cf6cf 100644 --- a/src/Hyperledger.Aries.Routing.Mediator/MediatorDiscoveryMiddleware.cs +++ b/legacy/src/Hyperledger.Aries.Routing.Mediator/MediatorDiscoveryMiddleware.cs @@ -1,65 +1,65 @@ -using System; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Agents.Edge; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Extensions; -using Hyperledger.Aries.Features.Handshakes.Connection; -using Hyperledger.Aries.Features.Handshakes.Connection.Models; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; - -namespace Hyperledger.Aries.Routing -{ - public class MediatorDiscoveryMiddleware : IMiddleware - { - private readonly AgentOptions options; - private readonly IProvisioningService provisioningService; - private readonly IConnectionService connectionService; - private readonly IAgentProvider agentProvider; - - public MediatorDiscoveryMiddleware( - IOptions options, - IProvisioningService provisioningService, - IConnectionService connectionService, - IAgentProvider agentProvider) - { - this.options = options.Value; - this.provisioningService = provisioningService; - this.connectionService = connectionService; - this.agentProvider = agentProvider; - } - - public async Task InvokeAsync(HttpContext context, RequestDelegate next) - { - var agentConfiguration = await GetConfigurationAsync(); - context.Response.ContentType = "application/json"; - context.Response.StatusCode = (int)HttpStatusCode.OK; - await context.Response.WriteAsync(agentConfiguration.ToJson()); - } - - public async Task GetConfigurationAsync() - { - var agentContext = await agentProvider.GetContextAsync(); - var provisioningRecord = await provisioningService.GetProvisioningAsync(agentContext.Wallet); - var connectionId = provisioningRecord.GetTag(MediatorProvisioningService.EdgeInvitationTagName); - - if (connectionId == null) - { - throw new Exception("This agent hasn't been provisioned as mediator agent"); - } - var inviation = await connectionService.GetAsync(agentContext, connectionId); - - var agentConfiguration = new AgentPublicConfiguration - { - ServiceEndpoint = provisioningRecord.Endpoint.Uri, - RoutingKey = provisioningRecord.Endpoint.Verkey.First(), - Invitation = inviation.GetTag(MediatorProvisioningService.InvitationTagName) - .ToObject() - }; - return agentConfiguration; - } - } -} +using System; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Agents.Edge; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Extensions; +using Hyperledger.Aries.Features.Handshakes.Connection; +using Hyperledger.Aries.Features.Handshakes.Connection.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; + +namespace Hyperledger.Aries.Routing +{ + public class MediatorDiscoveryMiddleware : IMiddleware + { + private readonly AgentOptions options; + private readonly IProvisioningService provisioningService; + private readonly IConnectionService connectionService; + private readonly IAgentProvider agentProvider; + + public MediatorDiscoveryMiddleware( + IOptions options, + IProvisioningService provisioningService, + IConnectionService connectionService, + IAgentProvider agentProvider) + { + this.options = options.Value; + this.provisioningService = provisioningService; + this.connectionService = connectionService; + this.agentProvider = agentProvider; + } + + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + var agentConfiguration = await GetConfigurationAsync(); + context.Response.ContentType = "application/json"; + context.Response.StatusCode = (int)HttpStatusCode.OK; + await context.Response.WriteAsync(agentConfiguration.ToJson()); + } + + public async Task GetConfigurationAsync() + { + var agentContext = await agentProvider.GetContextAsync(); + var provisioningRecord = await provisioningService.GetProvisioningAsync(agentContext.Wallet); + var connectionId = provisioningRecord.GetTag(MediatorProvisioningService.EdgeInvitationTagName); + + if (connectionId == null) + { + throw new Exception("This agent hasn't been provisioned as mediator agent"); + } + var inviation = await connectionService.GetAsync(agentContext, connectionId); + + var agentConfiguration = new AgentPublicConfiguration + { + ServiceEndpoint = provisioningRecord.Endpoint.Uri, + RoutingKey = provisioningRecord.Endpoint.Verkey.First(), + Invitation = inviation.GetTag(MediatorProvisioningService.InvitationTagName) + .ToObject() + }; + return agentConfiguration; + } + } +} diff --git a/src/Hyperledger.Aries.Routing.Mediator/MediatorProvisioningService.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/MediatorProvisioningService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/MediatorProvisioningService.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/MediatorProvisioningService.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Records/DeviceInfoRecord.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Records/DeviceInfoRecord.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Records/DeviceInfoRecord.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Records/DeviceInfoRecord.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Records/InboxItemRecord.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Records/InboxItemRecord.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Records/InboxItemRecord.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Records/InboxItemRecord.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Records/InboxRecord.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Records/InboxRecord.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Records/InboxRecord.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Records/InboxRecord.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Records/RouteRecord.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Records/RouteRecord.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Records/RouteRecord.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Records/RouteRecord.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Storage/DefaultStorageService.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Storage/DefaultStorageService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Storage/DefaultStorageService.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Storage/DefaultStorageService.cs diff --git a/src/Hyperledger.Aries.Routing.Mediator/Storage/IStorageService.cs b/legacy/src/Hyperledger.Aries.Routing.Mediator/Storage/IStorageService.cs similarity index 100% rename from src/Hyperledger.Aries.Routing.Mediator/Storage/IStorageService.cs rename to legacy/src/Hyperledger.Aries.Routing.Mediator/Storage/IStorageService.cs diff --git a/legacy/src/Hyperledger.Aries.Routing.Mediator/buildTransitive/Legacy.Deprecated.targets b/legacy/src/Hyperledger.Aries.Routing.Mediator/buildTransitive/Legacy.Deprecated.targets new file mode 100644 index 00000000..76510c8b --- /dev/null +++ b/legacy/src/Hyperledger.Aries.Routing.Mediator/buildTransitive/Legacy.Deprecated.targets @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Hyperledger.Aries.Routing/AddDeviceInfoMessage.cs b/legacy/src/Hyperledger.Aries.Routing/AddDeviceInfoMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/AddDeviceInfoMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/AddDeviceInfoMessage.cs diff --git a/src/Hyperledger.Aries.Routing/AddRouteMessage.cs b/legacy/src/Hyperledger.Aries.Routing/AddRouteMessage.cs similarity index 98% rename from src/Hyperledger.Aries.Routing/AddRouteMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/AddRouteMessage.cs index f31eeae4..218add40 100644 --- a/src/Hyperledger.Aries.Routing/AddRouteMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/AddRouteMessage.cs @@ -1,28 +1,28 @@ -using System; +using System; using Hyperledger.Aries.Agents; namespace Hyperledger.Aries.Routing -{ - /// - /// Add Route Message - /// - /// +{ + /// + /// Add Route Message + /// + /// public class AddRouteMessage : AgentMessage { - /// - /// Initializes a new instance of the class. - /// + /// + /// Initializes a new instance of the class. + /// public AddRouteMessage() { Id = Guid.NewGuid().ToString(); Type = RoutingTypeNames.AddRouteMessage; } - /// - /// Gets or sets the route destination. - /// - /// - /// The route destination. - /// + /// + /// Gets or sets the route destination. + /// + /// + /// The route destination. + /// public string RouteDestination { get; set; } } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/AgentPublicConfiguration.cs b/legacy/src/Hyperledger.Aries.Routing/AgentPublicConfiguration.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/AgentPublicConfiguration.cs rename to legacy/src/Hyperledger.Aries.Routing/AgentPublicConfiguration.cs diff --git a/src/Hyperledger.Aries.Routing/BackupTypeNames.cs b/legacy/src/Hyperledger.Aries.Routing/BackupTypeNames.cs similarity index 98% rename from src/Hyperledger.Aries.Routing/BackupTypeNames.cs rename to legacy/src/Hyperledger.Aries.Routing/BackupTypeNames.cs index 50c05d6d..26922b44 100644 --- a/src/Hyperledger.Aries.Routing/BackupTypeNames.cs +++ b/legacy/src/Hyperledger.Aries.Routing/BackupTypeNames.cs @@ -1,16 +1,16 @@ -using Hyperledger.Aries.Agents; - -namespace Hyperledger.Aries.Routing -{ - public static class BackupTypeNames - { - public const string RetrieveBackupAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/retrieve_backup"; - public const string RetrieveBackupResponseAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/retrieve_backup_response"; - - public const string StoreBackupAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/store_backup"; - public const string StoreBackupResponseAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/store_backup_response"; - - public const string ListBackupsAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/list_backups"; - public const string ListBackupsResponseAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/list_backups_response"; - } +using Hyperledger.Aries.Agents; + +namespace Hyperledger.Aries.Routing +{ + public static class BackupTypeNames + { + public const string RetrieveBackupAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/retrieve_backup"; + public const string RetrieveBackupResponseAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/retrieve_backup_response"; + + public const string StoreBackupAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/store_backup"; + public const string StoreBackupResponseAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/store_backup_response"; + + public const string ListBackupsAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/list_backups"; + public const string ListBackupsResponseAgentMessage = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/backup_restore/1.0/list_backups_response"; + } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/CreateInboxMessage.cs b/legacy/src/Hyperledger.Aries.Routing/CreateInboxMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/CreateInboxMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/CreateInboxMessage.cs diff --git a/src/Hyperledger.Aries.Routing/CreateInboxResponseMessage.cs b/legacy/src/Hyperledger.Aries.Routing/CreateInboxResponseMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/CreateInboxResponseMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/CreateInboxResponseMessage.cs diff --git a/src/Hyperledger.Aries.Routing/DeleteInboxItemsMessage.cs b/legacy/src/Hyperledger.Aries.Routing/DeleteInboxItemsMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/DeleteInboxItemsMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/DeleteInboxItemsMessage.cs diff --git a/src/Hyperledger.Aries.Routing/GetInboxItemsMessage.cs b/legacy/src/Hyperledger.Aries.Routing/GetInboxItemsMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/GetInboxItemsMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/GetInboxItemsMessage.cs diff --git a/src/Hyperledger.Aries.Routing/GetInboxItemsResponseMessage.cs b/legacy/src/Hyperledger.Aries.Routing/GetInboxItemsResponseMessage.cs similarity index 98% rename from src/Hyperledger.Aries.Routing/GetInboxItemsResponseMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/GetInboxItemsResponseMessage.cs index 37cbde85..f291c750 100644 --- a/src/Hyperledger.Aries.Routing/GetInboxItemsResponseMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/GetInboxItemsResponseMessage.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Hyperledger.Aries.Agents; @@ -6,21 +6,21 @@ namespace Hyperledger.Aries.Routing { public class GetInboxItemsResponseMessage : AgentMessage { - /// - /// Initializes a new instance of the class. - /// + /// + /// Initializes a new instance of the class. + /// public GetInboxItemsResponseMessage() { Id = Guid.NewGuid().ToString(); Type = RoutingTypeNames.GetInboxItemsResponseMessage; } - /// - /// Gets or sets the items. - /// - /// - /// The items. - /// + /// + /// Gets or sets the items. + /// + /// + /// The items. + /// public IEnumerable Items { get; set; } } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/Hyperledger.Aries.Routing.csproj b/legacy/src/Hyperledger.Aries.Routing/Hyperledger.Aries.Routing.csproj similarity index 83% rename from src/Hyperledger.Aries.Routing/Hyperledger.Aries.Routing.csproj rename to legacy/src/Hyperledger.Aries.Routing/Hyperledger.Aries.Routing.csproj index ff816e34..ba4e36d2 100644 --- a/src/Hyperledger.Aries.Routing/Hyperledger.Aries.Routing.csproj +++ b/legacy/src/Hyperledger.Aries.Routing/Hyperledger.Aries.Routing.csproj @@ -1,14 +1,16 @@ - - - WalletFramework.Routing - bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Routing.xml - - - - - - - - - - + + + WalletFramework.Routing + bin\$(Configuration)\$(TargetFramework)\Hyperledger.Aries.Routing.xml + false + netstandard2.1 + + + + + + + + + + diff --git a/src/Hyperledger.Aries.Routing/InboxItemEvent.cs b/legacy/src/Hyperledger.Aries.Routing/InboxItemEvent.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/InboxItemEvent.cs rename to legacy/src/Hyperledger.Aries.Routing/InboxItemEvent.cs diff --git a/src/Hyperledger.Aries.Routing/InboxItemMessage.cs b/legacy/src/Hyperledger.Aries.Routing/InboxItemMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/InboxItemMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/InboxItemMessage.cs diff --git a/src/Hyperledger.Aries.Routing/ListBackupsAgentMessage.cs b/legacy/src/Hyperledger.Aries.Routing/ListBackupsAgentMessage.cs similarity index 96% rename from src/Hyperledger.Aries.Routing/ListBackupsAgentMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/ListBackupsAgentMessage.cs index bd1d2449..cf64bee1 100644 --- a/src/Hyperledger.Aries.Routing/ListBackupsAgentMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/ListBackupsAgentMessage.cs @@ -1,24 +1,24 @@ -using System; -using Hyperledger.Aries.Agents; - -namespace Hyperledger.Aries.Routing -{ - public class ListBackupsAgentMessage : AgentMessage - { - /// - /// Initializes a new instance of the class. - /// - public ListBackupsAgentMessage() - { - Id = new Guid().ToString(); - Type = BackupTypeNames.ListBackupsAgentMessage; - } - /// - /// Gets or sets the backup identifier. - /// - /// - /// The backup identifier. - /// - public string BackupId { get; set; } - } +using System; +using Hyperledger.Aries.Agents; + +namespace Hyperledger.Aries.Routing +{ + public class ListBackupsAgentMessage : AgentMessage + { + /// + /// Initializes a new instance of the class. + /// + public ListBackupsAgentMessage() + { + Id = new Guid().ToString(); + Type = BackupTypeNames.ListBackupsAgentMessage; + } + /// + /// Gets or sets the backup identifier. + /// + /// + /// The backup identifier. + /// + public string BackupId { get; set; } + } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/ListBackupsResponseAgentMessage.cs b/legacy/src/Hyperledger.Aries.Routing/ListBackupsResponseAgentMessage.cs similarity index 96% rename from src/Hyperledger.Aries.Routing/ListBackupsResponseAgentMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/ListBackupsResponseAgentMessage.cs index b14193a3..d05127c3 100644 --- a/src/Hyperledger.Aries.Routing/ListBackupsResponseAgentMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/ListBackupsResponseAgentMessage.cs @@ -1,17 +1,17 @@ -using Hyperledger.Aries.Agents; -using System; -using System.Collections.Generic; - -namespace Hyperledger.Aries.Routing -{ - public class ListBackupsResponseAgentMessage : AgentMessage - { - public ListBackupsResponseAgentMessage() - { - Id = Guid.NewGuid().ToString(); - Type = BackupTypeNames.ListBackupsResponseAgentMessage; - } - - public IEnumerable BackupList { get; set; } - } +using Hyperledger.Aries.Agents; +using System; +using System.Collections.Generic; + +namespace Hyperledger.Aries.Routing +{ + public class ListBackupsResponseAgentMessage : AgentMessage + { + public ListBackupsResponseAgentMessage() + { + Id = Guid.NewGuid().ToString(); + Type = BackupTypeNames.ListBackupsResponseAgentMessage; + } + + public IEnumerable BackupList { get; set; } + } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/RestoreInboxMessage.cs b/legacy/src/Hyperledger.Aries.Routing/RestoreInboxMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/RestoreInboxMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/RestoreInboxMessage.cs diff --git a/src/Hyperledger.Aries.Routing/RetrieveBackupAgentMessage.cs b/legacy/src/Hyperledger.Aries.Routing/RetrieveBackupAgentMessage.cs similarity index 96% rename from src/Hyperledger.Aries.Routing/RetrieveBackupAgentMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/RetrieveBackupAgentMessage.cs index cb613565..c2500a80 100644 --- a/src/Hyperledger.Aries.Routing/RetrieveBackupAgentMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/RetrieveBackupAgentMessage.cs @@ -1,17 +1,17 @@ -using Hyperledger.Aries.Agents; -using System; - -namespace Hyperledger.Aries.Routing -{ - public class RetrieveBackupAgentMessage : AgentMessage - { - public RetrieveBackupAgentMessage() - { - Id = Guid.NewGuid().ToString(); - Type = BackupTypeNames.RetrieveBackupAgentMessage; - } - - public string BackupId { get; set; } - public string Signature { get; set; } - } +using Hyperledger.Aries.Agents; +using System; + +namespace Hyperledger.Aries.Routing +{ + public class RetrieveBackupAgentMessage : AgentMessage + { + public RetrieveBackupAgentMessage() + { + Id = Guid.NewGuid().ToString(); + Type = BackupTypeNames.RetrieveBackupAgentMessage; + } + + public string BackupId { get; set; } + public string Signature { get; set; } + } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/RetrieveBackupResponseAgentMessage.cs b/legacy/src/Hyperledger.Aries.Routing/RetrieveBackupResponseAgentMessage.cs similarity index 96% rename from src/Hyperledger.Aries.Routing/RetrieveBackupResponseAgentMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/RetrieveBackupResponseAgentMessage.cs index 1b4d3239..d1107fa3 100644 --- a/src/Hyperledger.Aries.Routing/RetrieveBackupResponseAgentMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/RetrieveBackupResponseAgentMessage.cs @@ -1,18 +1,18 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Decorators.Attachments; -using System; -using System.Collections.Generic; - -namespace Hyperledger.Aries.Routing -{ - public class RetrieveBackupResponseAgentMessage : AgentMessage - { - public RetrieveBackupResponseAgentMessage() - { - Id = Guid.NewGuid().ToString(); - Type = BackupTypeNames.RetrieveBackupResponseAgentMessage; - } - - public List Payload { get; set; } - } +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Decorators.Attachments; +using System; +using System.Collections.Generic; + +namespace Hyperledger.Aries.Routing +{ + public class RetrieveBackupResponseAgentMessage : AgentMessage + { + public RetrieveBackupResponseAgentMessage() + { + Id = Guid.NewGuid().ToString(); + Type = BackupTypeNames.RetrieveBackupResponseAgentMessage; + } + + public List Payload { get; set; } + } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/RoutingTypeNames.cs b/legacy/src/Hyperledger.Aries.Routing/RoutingTypeNames.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/RoutingTypeNames.cs rename to legacy/src/Hyperledger.Aries.Routing/RoutingTypeNames.cs diff --git a/src/Hyperledger.Aries.Routing/StoreBackupAgentMessage.cs b/legacy/src/Hyperledger.Aries.Routing/StoreBackupAgentMessage.cs similarity index 96% rename from src/Hyperledger.Aries.Routing/StoreBackupAgentMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/StoreBackupAgentMessage.cs index 58d42e5b..9c9b97c7 100644 --- a/src/Hyperledger.Aries.Routing/StoreBackupAgentMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/StoreBackupAgentMessage.cs @@ -1,20 +1,20 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Decorators.Attachments; -using System; -using System.Collections.Generic; - -namespace Hyperledger.Aries.Routing -{ - public class StoreBackupAgentMessage : AgentMessage - { - public StoreBackupAgentMessage() - { - Id = Guid.NewGuid().ToString(); - Type = BackupTypeNames.StoreBackupAgentMessage; - } - - public string BackupId { get; set; } - public List Payload { get; set; } - public string PayloadSignature { get; set; } - } +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Decorators.Attachments; +using System; +using System.Collections.Generic; + +namespace Hyperledger.Aries.Routing +{ + public class StoreBackupAgentMessage : AgentMessage + { + public StoreBackupAgentMessage() + { + Id = Guid.NewGuid().ToString(); + Type = BackupTypeNames.StoreBackupAgentMessage; + } + + public string BackupId { get; set; } + public List Payload { get; set; } + public string PayloadSignature { get; set; } + } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/StoreBackupResponseAgentMessage.cs b/legacy/src/Hyperledger.Aries.Routing/StoreBackupResponseAgentMessage.cs similarity index 96% rename from src/Hyperledger.Aries.Routing/StoreBackupResponseAgentMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/StoreBackupResponseAgentMessage.cs index 464cd8f6..2b74d5d3 100644 --- a/src/Hyperledger.Aries.Routing/StoreBackupResponseAgentMessage.cs +++ b/legacy/src/Hyperledger.Aries.Routing/StoreBackupResponseAgentMessage.cs @@ -1,15 +1,15 @@ -using Hyperledger.Aries.Agents; -using System; - -namespace Hyperledger.Aries.Routing -{ - public class StoreBackupResponseAgentMessage : AgentMessage - { - public StoreBackupResponseAgentMessage() - { - Id = Guid.NewGuid().ToString(); - Type = BackupTypeNames.StoreBackupResponseAgentMessage; - } - public DateTimeOffset BackupTimestamp { get; set; } - } +using Hyperledger.Aries.Agents; +using System; + +namespace Hyperledger.Aries.Routing +{ + public class StoreBackupResponseAgentMessage : AgentMessage + { + public StoreBackupResponseAgentMessage() + { + Id = Guid.NewGuid().ToString(); + Type = BackupTypeNames.StoreBackupResponseAgentMessage; + } + public DateTimeOffset BackupTimestamp { get; set; } + } } \ No newline at end of file diff --git a/src/Hyperledger.Aries.Routing/UpsertDeviceInfoMessage.cs b/legacy/src/Hyperledger.Aries.Routing/UpsertDeviceInfoMessage.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/UpsertDeviceInfoMessage.cs rename to legacy/src/Hyperledger.Aries.Routing/UpsertDeviceInfoMessage.cs diff --git a/src/Hyperledger.Aries.Routing/Utils.cs b/legacy/src/Hyperledger.Aries.Routing/Utils.cs similarity index 100% rename from src/Hyperledger.Aries.Routing/Utils.cs rename to legacy/src/Hyperledger.Aries.Routing/Utils.cs diff --git a/src/Hyperledger.Aries/Agents/Abstractions/IAgent.cs b/legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgent.cs similarity index 96% rename from src/Hyperledger.Aries/Agents/Abstractions/IAgent.cs rename to legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgent.cs index 64607cc9..b1174f97 100644 --- a/src/Hyperledger.Aries/Agents/Abstractions/IAgent.cs +++ b/legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgent.cs @@ -1,31 +1,31 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Hyperledger.Aries.Agents -{ - /// - /// Agent. - /// - public interface IAgent - { - /// - /// Gets the service provider used by this agent instance - /// - IServiceProvider Provider { get; } - - /// - /// Processes the async. - /// - /// The async. - /// Context. - /// Message context. - Task ProcessAsync(IAgentContext context, MessageContext messageContext); - - /// - /// Gets the handlers. - /// - /// The handlers. - IList Handlers { get; } - } -} +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Hyperledger.Aries.Agents +{ + /// + /// Agent. + /// + public interface IAgent + { + /// + /// Gets the service provider used by this agent instance + /// + IServiceProvider Provider { get; } + + /// + /// Processes the async. + /// + /// The async. + /// Context. + /// Message context. + Task ProcessAsync(IAgentContext context, MessageContext messageContext); + + /// + /// Gets the handlers. + /// + /// The handlers. + IList Handlers { get; } + } +} diff --git a/src/Hyperledger.Aries/Agents/Abstractions/IAgentContext.cs b/legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgentContext.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Abstractions/IAgentContext.cs rename to legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgentContext.cs diff --git a/src/Hyperledger.Aries/Agents/Abstractions/IAgentMiddleware.cs b/legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgentMiddleware.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Abstractions/IAgentMiddleware.cs rename to legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgentMiddleware.cs diff --git a/src/Hyperledger.Aries/Agents/Abstractions/IAgentProvider.cs b/legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgentProvider.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Abstractions/IAgentProvider.cs rename to legacy/src/Hyperledger.Aries/Agents/Abstractions/IAgentProvider.cs diff --git a/src/Hyperledger.Aries/Agents/Abstractions/IMessageHandler.cs b/legacy/src/Hyperledger.Aries/Agents/Abstractions/IMessageHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Abstractions/IMessageHandler.cs rename to legacy/src/Hyperledger.Aries/Agents/Abstractions/IMessageHandler.cs diff --git a/src/Hyperledger.Aries/Agents/AgentBase.cs b/legacy/src/Hyperledger.Aries/Agents/AgentBase.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/AgentBase.cs rename to legacy/src/Hyperledger.Aries/Agents/AgentBase.cs diff --git a/src/Hyperledger.Aries/Agents/AgentContext.cs b/legacy/src/Hyperledger.Aries/Agents/AgentContext.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/AgentContext.cs rename to legacy/src/Hyperledger.Aries/Agents/AgentContext.cs diff --git a/src/Hyperledger.Aries/Agents/Converters/AgentEndpointJsonConverter.cs b/legacy/src/Hyperledger.Aries/Agents/Converters/AgentEndpointJsonConverter.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Converters/AgentEndpointJsonConverter.cs rename to legacy/src/Hyperledger.Aries/Agents/Converters/AgentEndpointJsonConverter.cs diff --git a/src/Hyperledger.Aries/Agents/Converters/AgentMessageReader.cs b/legacy/src/Hyperledger.Aries/Agents/Converters/AgentMessageReader.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Converters/AgentMessageReader.cs rename to legacy/src/Hyperledger.Aries/Agents/Converters/AgentMessageReader.cs diff --git a/src/Hyperledger.Aries/Agents/Converters/AgentMessageWriter.cs b/legacy/src/Hyperledger.Aries/Agents/Converters/AgentMessageWriter.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Converters/AgentMessageWriter.cs rename to legacy/src/Hyperledger.Aries/Agents/Converters/AgentMessageWriter.cs diff --git a/src/Hyperledger.Aries/Agents/DefaultAgent.cs b/legacy/src/Hyperledger.Aries/Agents/DefaultAgent.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/DefaultAgent.cs rename to legacy/src/Hyperledger.Aries/Agents/DefaultAgent.cs diff --git a/src/Hyperledger.Aries/Agents/DefaultAgentContext.cs b/legacy/src/Hyperledger.Aries/Agents/DefaultAgentContext.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/DefaultAgentContext.cs rename to legacy/src/Hyperledger.Aries/Agents/DefaultAgentContext.cs diff --git a/src/Hyperledger.Aries/Agents/DefaultAgentProvider.cs b/legacy/src/Hyperledger.Aries/Agents/DefaultAgentProvider.cs similarity index 97% rename from src/Hyperledger.Aries/Agents/DefaultAgentProvider.cs rename to legacy/src/Hyperledger.Aries/Agents/DefaultAgentProvider.cs index 4d9b1bb3..26a84f1a 100644 --- a/src/Hyperledger.Aries/Agents/DefaultAgentProvider.cs +++ b/legacy/src/Hyperledger.Aries/Agents/DefaultAgentProvider.cs @@ -1,61 +1,61 @@ -using System.Threading.Tasks; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Contracts; -using Hyperledger.Aries.Ledger; -using Hyperledger.Aries.Storage; -using Microsoft.Extensions.Options; - -namespace Hyperledger.Aries.Agents -{ - /// - public class DefaultAgentProvider : IAgentProvider - { - private readonly AgentOptions _agentOptions; - private readonly IAgent _defaultAgent; - private readonly IWalletService _walletService; - private readonly IPoolService _poolService; - - /// - /// Initializes a new instance of the class. - /// - /// - /// Default agent. - /// Wallet service. - /// Pool service. - public DefaultAgentProvider( - IOptions agentOptions, - IAgent defaultAgent, - IWalletService walletService, - IPoolService poolService) - { - _agentOptions = agentOptions.Value; - _defaultAgent = defaultAgent; - _walletService = walletService; - _poolService = poolService; - } - - /// - public Task GetAgentAsync(params object[] args) - { - return Task.FromResult(_defaultAgent); - } - - /// - public async Task GetContextAsync(params object[] args) - { - var agent = await GetAgentAsync(args); - return new DefaultAgentContext - { - Wallet = await _walletService.GetWalletAsync( - configuration: _agentOptions.WalletConfiguration, - credentials: _agentOptions.WalletCredentials), - Pool = new PoolAwaitable(() => _poolService.GetPoolAsync( - poolName: _agentOptions.PoolName, - protocolVersion: _agentOptions.ProtocolVersion)), - SupportedMessages = agent.GetSupportedMessageTypes(), - Agent = await GetAgentAsync(args), - UseMessageTypesHttps = _agentOptions.UseMessageTypesHttps - }; - } - } -} +using System.Threading.Tasks; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Contracts; +using Hyperledger.Aries.Ledger; +using Hyperledger.Aries.Storage; +using Microsoft.Extensions.Options; + +namespace Hyperledger.Aries.Agents +{ + /// + public class DefaultAgentProvider : IAgentProvider + { + private readonly AgentOptions _agentOptions; + private readonly IAgent _defaultAgent; + private readonly IWalletService _walletService; + private readonly IPoolService _poolService; + + /// + /// Initializes a new instance of the class. + /// + /// + /// Default agent. + /// Wallet service. + /// Pool service. + public DefaultAgentProvider( + IOptions agentOptions, + IAgent defaultAgent, + IWalletService walletService, + IPoolService poolService) + { + _agentOptions = agentOptions.Value; + _defaultAgent = defaultAgent; + _walletService = walletService; + _poolService = poolService; + } + + /// + public Task GetAgentAsync(params object[] args) + { + return Task.FromResult(_defaultAgent); + } + + /// + public async Task GetContextAsync(params object[] args) + { + var agent = await GetAgentAsync(args); + return new DefaultAgentContext + { + Wallet = await _walletService.GetWalletAsync( + configuration: _agentOptions.WalletConfiguration, + credentials: _agentOptions.WalletCredentials), + Pool = new PoolAwaitable(() => _poolService.GetPoolAsync( + poolName: _agentOptions.PoolName, + protocolVersion: _agentOptions.ProtocolVersion)), + SupportedMessages = agent.GetSupportedMessageTypes(), + Agent = await GetAgentAsync(args), + UseMessageTypesHttps = _agentOptions.UseMessageTypesHttps + }; + } + } +} diff --git a/src/Hyperledger.Aries/Agents/Extensions/AgentFrameworkBuilderExtensions.cs b/legacy/src/Hyperledger.Aries/Agents/Extensions/AgentFrameworkBuilderExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Extensions/AgentFrameworkBuilderExtensions.cs rename to legacy/src/Hyperledger.Aries/Agents/Extensions/AgentFrameworkBuilderExtensions.cs diff --git a/src/Hyperledger.Aries/Agents/Extensions/AgentsExtensions.cs b/legacy/src/Hyperledger.Aries/Agents/Extensions/AgentsExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Extensions/AgentsExtensions.cs rename to legacy/src/Hyperledger.Aries/Agents/Extensions/AgentsExtensions.cs diff --git a/src/Hyperledger.Aries/Agents/Extensions/ServiceCollectionExtensions.cs b/legacy/src/Hyperledger.Aries/Agents/Extensions/ServiceCollectionExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Extensions/ServiceCollectionExtensions.cs rename to legacy/src/Hyperledger.Aries/Agents/Extensions/ServiceCollectionExtensions.cs diff --git a/src/Hyperledger.Aries/Agents/MessageHandlerBase.cs b/legacy/src/Hyperledger.Aries/Agents/MessageHandlerBase.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/MessageHandlerBase.cs rename to legacy/src/Hyperledger.Aries/Agents/MessageHandlerBase.cs diff --git a/src/Hyperledger.Aries/Agents/MessageType.cs b/legacy/src/Hyperledger.Aries/Agents/MessageType.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/MessageType.cs rename to legacy/src/Hyperledger.Aries/Agents/MessageType.cs diff --git a/src/Hyperledger.Aries/Agents/MessageTypes.cs b/legacy/src/Hyperledger.Aries/Agents/MessageTypes.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/MessageTypes.cs rename to legacy/src/Hyperledger.Aries/Agents/MessageTypes.cs diff --git a/src/Hyperledger.Aries/Agents/MessageTypesHttps.cs b/legacy/src/Hyperledger.Aries/Agents/MessageTypesHttps.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/MessageTypesHttps.cs rename to legacy/src/Hyperledger.Aries/Agents/MessageTypesHttps.cs diff --git a/src/Hyperledger.Aries/Agents/Models/AgentEndpoint.cs b/legacy/src/Hyperledger.Aries/Agents/Models/AgentEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Models/AgentEndpoint.cs rename to legacy/src/Hyperledger.Aries/Agents/Models/AgentEndpoint.cs diff --git a/src/Hyperledger.Aries/Agents/Models/AgentMessage.cs b/legacy/src/Hyperledger.Aries/Agents/Models/AgentMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Models/AgentMessage.cs rename to legacy/src/Hyperledger.Aries/Agents/Models/AgentMessage.cs diff --git a/src/Hyperledger.Aries/Agents/Models/AgentOwner.cs b/legacy/src/Hyperledger.Aries/Agents/Models/AgentOwner.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Models/AgentOwner.cs rename to legacy/src/Hyperledger.Aries/Agents/Models/AgentOwner.cs diff --git a/src/Hyperledger.Aries/Agents/Models/MessageContext.cs b/legacy/src/Hyperledger.Aries/Agents/Models/MessageContext.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Models/MessageContext.cs rename to legacy/src/Hyperledger.Aries/Agents/Models/MessageContext.cs diff --git a/src/Hyperledger.Aries/Agents/Models/PackedMessageContext.cs b/legacy/src/Hyperledger.Aries/Agents/Models/PackedMessageContext.cs similarity index 97% rename from src/Hyperledger.Aries/Agents/Models/PackedMessageContext.cs rename to legacy/src/Hyperledger.Aries/Agents/Models/PackedMessageContext.cs index bbdca88c..bde5a35a 100644 --- a/src/Hyperledger.Aries/Agents/Models/PackedMessageContext.cs +++ b/legacy/src/Hyperledger.Aries/Agents/Models/PackedMessageContext.cs @@ -1,48 +1,48 @@ -using Hyperledger.Aries.Extensions; -using Hyperledger.Aries.Features.Handshakes.Common; -using Newtonsoft.Json.Linq; - -namespace Hyperledger.Aries.Agents -{ - /// - /// Represents an agent message in encrypted (packed) format - /// - public class PackedMessageContext : MessageContext - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public PackedMessageContext(byte[] message) : base(message, true) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// - public PackedMessageContext(string message) : base(message, true) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - public PackedMessageContext(JObject message) : base(message.ToJson(), true) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - public PackedMessageContext(string message, ConnectionRecord connection) : base(message, true, connection) - { - } - } -} +using Hyperledger.Aries.Extensions; +using Hyperledger.Aries.Features.Handshakes.Common; +using Newtonsoft.Json.Linq; + +namespace Hyperledger.Aries.Agents +{ + /// + /// Represents an agent message in encrypted (packed) format + /// + public class PackedMessageContext : MessageContext + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public PackedMessageContext(byte[] message) : base(message, true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// + public PackedMessageContext(string message) : base(message, true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + public PackedMessageContext(JObject message) : base(message.ToJson(), true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public PackedMessageContext(string message, ConnectionRecord connection) : base(message, true, connection) + { + } + } +} diff --git a/src/Hyperledger.Aries/Agents/Models/UnpackedMessageContext.cs b/legacy/src/Hyperledger.Aries/Agents/Models/UnpackedMessageContext.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Models/UnpackedMessageContext.cs rename to legacy/src/Hyperledger.Aries/Agents/Models/UnpackedMessageContext.cs diff --git a/src/Hyperledger.Aries/Agents/Transport/DefaultMessageService.cs b/legacy/src/Hyperledger.Aries/Agents/Transport/DefaultMessageService.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Transport/DefaultMessageService.cs rename to legacy/src/Hyperledger.Aries/Agents/Transport/DefaultMessageService.cs diff --git a/src/Hyperledger.Aries/Agents/Transport/HttpMessageDispatcher.cs b/legacy/src/Hyperledger.Aries/Agents/Transport/HttpMessageDispatcher.cs similarity index 97% rename from src/Hyperledger.Aries/Agents/Transport/HttpMessageDispatcher.cs rename to legacy/src/Hyperledger.Aries/Agents/Transport/HttpMessageDispatcher.cs index 508e8b64..0687ed05 100644 --- a/src/Hyperledger.Aries/Agents/Transport/HttpMessageDispatcher.cs +++ b/legacy/src/Hyperledger.Aries/Agents/Transport/HttpMessageDispatcher.cs @@ -1,66 +1,66 @@ -using System; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; - -namespace Hyperledger.Aries.Agents -{ - /// - /// Http message dispatcher. - /// - public class HttpMessageDispatcher : IMessageDispatcher - { - /// The HTTP client - protected readonly HttpClient HttpClient; - - /// - /// Default constructor. - /// - /// The HTTP client factory. - public HttpMessageDispatcher(IHttpClientFactory httpClientFactory) - { - HttpClient = httpClientFactory.CreateClient(); - } - - /// - public string[] TransportSchemes => new[] { "http", "https" }; - - /// - public async Task DispatchAsync(Uri endpointUri, PackedMessageContext message) - { - var request = new HttpRequestMessage - { - RequestUri = endpointUri, - Method = HttpMethod.Post, - Content = new ByteArrayContent(message.Payload) - }; - - var encryptedEnvelopeContentType = new MediaTypeHeaderValue(DefaultMessageService.EncryptedEnvelopeMessageMimeType); - request.Content.Headers.ContentType = encryptedEnvelopeContentType; - - var response = await HttpClient.SendAsync(request); - - if (!response.IsSuccessStatusCode) - { - var responseBody = await response.Content.ReadAsStringAsync(); - throw new AriesFrameworkException( - ErrorCode.A2AMessageTransmissionError, $"Dispatch Failure. Endpoint:{endpointUri} Status: {response.StatusCode} Content: {responseBody}"); - } - - var responseContentType = response.Content?.Headers?.ContentType?.MediaType; - if(DefaultMessageService.SupportedMimeTypes.Contains(responseContentType)) - { - var rawContent = await response.Content.ReadAsByteArrayAsync(); - - //TODO this assumes all messages are packed - if (rawContent.Length > 0) - { - return new PackedMessageContext(rawContent); - } - } - - return null; - } - } -} +using System; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +namespace Hyperledger.Aries.Agents +{ + /// + /// Http message dispatcher. + /// + public class HttpMessageDispatcher : IMessageDispatcher + { + /// The HTTP client + protected readonly HttpClient HttpClient; + + /// + /// Default constructor. + /// + /// The HTTP client factory. + public HttpMessageDispatcher(IHttpClientFactory httpClientFactory) + { + HttpClient = httpClientFactory.CreateClient(); + } + + /// + public string[] TransportSchemes => new[] { "http", "https" }; + + /// + public async Task DispatchAsync(Uri endpointUri, PackedMessageContext message) + { + var request = new HttpRequestMessage + { + RequestUri = endpointUri, + Method = HttpMethod.Post, + Content = new ByteArrayContent(message.Payload) + }; + + var encryptedEnvelopeContentType = new MediaTypeHeaderValue(DefaultMessageService.EncryptedEnvelopeMessageMimeType); + request.Content.Headers.ContentType = encryptedEnvelopeContentType; + + var response = await HttpClient.SendAsync(request); + + if (!response.IsSuccessStatusCode) + { + var responseBody = await response.Content.ReadAsStringAsync(); + throw new AriesFrameworkException( + ErrorCode.A2AMessageTransmissionError, $"Dispatch Failure. Endpoint:{endpointUri} Status: {response.StatusCode} Content: {responseBody}"); + } + + var responseContentType = response.Content?.Headers?.ContentType?.MediaType; + if(DefaultMessageService.SupportedMimeTypes.Contains(responseContentType)) + { + var rawContent = await response.Content.ReadAsByteArrayAsync(); + + //TODO this assumes all messages are packed + if (rawContent.Length > 0) + { + return new PackedMessageContext(rawContent); + } + } + + return null; + } + } +} diff --git a/src/Hyperledger.Aries/Agents/Transport/IMessageDispatcher.cs b/legacy/src/Hyperledger.Aries/Agents/Transport/IMessageDispatcher.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Transport/IMessageDispatcher.cs rename to legacy/src/Hyperledger.Aries/Agents/Transport/IMessageDispatcher.cs diff --git a/src/Hyperledger.Aries/Agents/Transport/IMessageService.cs b/legacy/src/Hyperledger.Aries/Agents/Transport/IMessageService.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Transport/IMessageService.cs rename to legacy/src/Hyperledger.Aries/Agents/Transport/IMessageService.cs diff --git a/src/Hyperledger.Aries/Agents/Transport/MessageServiceExtensions.cs b/legacy/src/Hyperledger.Aries/Agents/Transport/MessageServiceExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Agents/Transport/MessageServiceExtensions.cs rename to legacy/src/Hyperledger.Aries/Agents/Transport/MessageServiceExtensions.cs diff --git a/src/Hyperledger.Aries/Common/AcknowledgeMessage.cs b/legacy/src/Hyperledger.Aries/Common/AcknowledgeMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Common/AcknowledgeMessage.cs rename to legacy/src/Hyperledger.Aries/Common/AcknowledgeMessage.cs diff --git a/src/Hyperledger.Aries/Common/AcknowledgementStatusConstants.cs b/legacy/src/Hyperledger.Aries/Common/AcknowledgementStatusConstants.cs similarity index 100% rename from src/Hyperledger.Aries/Common/AcknowledgementStatusConstants.cs rename to legacy/src/Hyperledger.Aries/Common/AcknowledgementStatusConstants.cs diff --git a/src/Hyperledger.Aries/Common/AgentFrameworkException.cs b/legacy/src/Hyperledger.Aries/Common/AgentFrameworkException.cs similarity index 100% rename from src/Hyperledger.Aries/Common/AgentFrameworkException.cs rename to legacy/src/Hyperledger.Aries/Common/AgentFrameworkException.cs diff --git a/src/Hyperledger.Aries/Common/ErrorCode.cs b/legacy/src/Hyperledger.Aries/Common/ErrorCode.cs similarity index 100% rename from src/Hyperledger.Aries/Common/ErrorCode.cs rename to legacy/src/Hyperledger.Aries/Common/ErrorCode.cs diff --git a/src/Hyperledger.Aries/Common/EventAggregator.cs b/legacy/src/Hyperledger.Aries/Common/EventAggregator.cs similarity index 100% rename from src/Hyperledger.Aries/Common/EventAggregator.cs rename to legacy/src/Hyperledger.Aries/Common/EventAggregator.cs diff --git a/src/Hyperledger.Aries/Common/FormattingExtensions.cs b/legacy/src/Hyperledger.Aries/Common/FormattingExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Common/FormattingExtensions.cs rename to legacy/src/Hyperledger.Aries/Common/FormattingExtensions.cs diff --git a/src/Hyperledger.Aries/Common/IEventAggregator.cs b/legacy/src/Hyperledger.Aries/Common/IEventAggregator.cs similarity index 100% rename from src/Hyperledger.Aries/Common/IEventAggregator.cs rename to legacy/src/Hyperledger.Aries/Common/IEventAggregator.cs diff --git a/src/Hyperledger.Aries/Common/LoggingEvents.cs b/legacy/src/Hyperledger.Aries/Common/LoggingEvents.cs similarity index 100% rename from src/Hyperledger.Aries/Common/LoggingEvents.cs rename to legacy/src/Hyperledger.Aries/Common/LoggingEvents.cs diff --git a/src/Hyperledger.Aries/Common/MediaTypes.cs b/legacy/src/Hyperledger.Aries/Common/MediaTypes.cs similarity index 100% rename from src/Hyperledger.Aries/Common/MediaTypes.cs rename to legacy/src/Hyperledger.Aries/Common/MediaTypes.cs diff --git a/src/Hyperledger.Aries/Common/ServiceMessageProcessingEvent.cs b/legacy/src/Hyperledger.Aries/Common/ServiceMessageProcessingEvent.cs similarity index 100% rename from src/Hyperledger.Aries/Common/ServiceMessageProcessingEvent.cs rename to legacy/src/Hyperledger.Aries/Common/ServiceMessageProcessingEvent.cs diff --git a/src/Hyperledger.Aries/Configuration/AgentOptions.cs b/legacy/src/Hyperledger.Aries/Configuration/AgentOptions.cs similarity index 96% rename from src/Hyperledger.Aries/Configuration/AgentOptions.cs rename to legacy/src/Hyperledger.Aries/Configuration/AgentOptions.cs index ad367bc3..a3c04c84 100644 --- a/src/Hyperledger.Aries/Configuration/AgentOptions.cs +++ b/legacy/src/Hyperledger.Aries/Configuration/AgentOptions.cs @@ -1,187 +1,187 @@ -using Hyperledger.Aries.Storage; -using Hyperledger.Aries.Utils; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Hyperledger.Aries.Configuration -{ - /// - /// Agent options - /// - public class AgentOptions - { - /// - /// Initializes a new instance of the class. - /// - public AgentOptions() - { - WalletConfiguration = new WalletConfiguration { Id = "DefaultWallet" }; - WalletCredentials = new WalletCredentials { Key = "DefaultKey" }; - } - - /// - /// Gets or sets the wallet configuration. - /// - /// The wallet configuration. - public WalletConfiguration WalletConfiguration - { - get; - set; - } - - /// - /// Gets or sets the wallet credentials. - /// - /// The wallet credentials. - public WalletCredentials WalletCredentials - { - get; - set; - } - /// - /// The DID of the issuer key pair - /// - /// - public string IssuerDid { get; set; } - - /// - /// The key of the - /// - /// - public string IssuerKeySeed { get; set; } - - /// - /// Gets or sets the agent did - /// - /// - public string AgentDid { get; set; } - - /// - /// Gets or sets the agent key generation seed - /// - /// - public string AgentKeySeed { get; set; } - - /// - /// Gets or sets the agent endpoint uri - /// - /// - public string EndpointUri { get; set; } - - /// - /// Gets or sets the agent name used in connection invitations - /// - /// - public string AgentName { get; set; } - - /// - /// Gets or sets the agent image uri - /// - /// - public string AgentImageUri { get; set; } - - /// - /// The verification key of the agent - /// - /// - public string AgentKey { get; set; } - - /// - /// Gets or sets the name of the pool. - /// - /// The name of the pool. - public string PoolName - { - get; - set; - } = "DefaultPool"; - - /// - /// Gets or sets the genesis filename. - /// - /// The genesis filename. - public string GenesisFilename - { - get; - set; - } - - /// - /// Gets or sets the protocol version of the nodes. - /// - /// - /// The protocol version. - /// - public int ProtocolVersion - { - get; - set; - } = 2; - - /// - /// Gets or sets the revocation registry URI path e.g. "/tails". - /// This path will be appended to the EndpointUri value. - /// This is used to optimize the ASP.NET Core middleware pipeline. - /// Default value is "/tails". The value must start with a slash '/'. - /// - /// - /// The revocation registry base URI path. - /// - public string RevocationRegistryUriPath { get; set; } = "/tails"; - - /// - /// Gets or sets the revocation registry directory where - /// revocation tails files will be stored. The default path - /// is ~/.indy_client/tails - /// - /// - /// The revocation registry directory. - /// - public string RevocationRegistryDirectory { get; set; } = EnvironmentUtils.GetTailsPath(); - - /// - /// Gets or sets the backup directory where physical backups will be stored. - /// This property is only used when running a mediator service. - /// - /// - /// The backup directory. - /// - public string BackupDirectory { get; set; } = Path.Combine(Path.GetTempPath(), "AriesBackups"); - - /// - /// Automatically respond to credential offers with a credential request. Default: false - /// - /// The name of the pool. - public bool AutoRespondCredentialOffer - { - get; - set; - } = false; - - /// - /// Automatically respond to credential request with corresponding credentials. Default: false - /// - /// The name of the pool. - public bool AutoRespondCredentialRequest - { - get; - set; - } = false; - - /// - /// Gets or sets the value for UseMessageTypesHttps. - /// Only affects messages created by the default services, - /// if you create additional messages you have to set the useMessageTypesHttps via ctor too - /// - /// True if to use UseMessageTypesHttps. - public bool UseMessageTypesHttps { get; set; } - - /// - /// Gets or sets the value for Metadata dictionary. - /// This dictionary can be used with InboxCreation on the mediator agent. - /// Data is stored under InboxRecord tags on the mediator agent. - /// - public Dictionary MetaData { get; set; } - } -} +using Hyperledger.Aries.Storage; +using Hyperledger.Aries.Utils; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Hyperledger.Aries.Configuration +{ + /// + /// Agent options + /// + public class AgentOptions + { + /// + /// Initializes a new instance of the class. + /// + public AgentOptions() + { + WalletConfiguration = new WalletConfiguration { Id = "DefaultWallet" }; + WalletCredentials = new WalletCredentials { Key = "DefaultKey" }; + } + + /// + /// Gets or sets the wallet configuration. + /// + /// The wallet configuration. + public WalletConfiguration WalletConfiguration + { + get; + set; + } + + /// + /// Gets or sets the wallet credentials. + /// + /// The wallet credentials. + public WalletCredentials WalletCredentials + { + get; + set; + } + /// + /// The DID of the issuer key pair + /// + /// + public string IssuerDid { get; set; } + + /// + /// The key of the + /// + /// + public string IssuerKeySeed { get; set; } + + /// + /// Gets or sets the agent did + /// + /// + public string AgentDid { get; set; } + + /// + /// Gets or sets the agent key generation seed + /// + /// + public string AgentKeySeed { get; set; } + + /// + /// Gets or sets the agent endpoint uri + /// + /// + public string EndpointUri { get; set; } + + /// + /// Gets or sets the agent name used in connection invitations + /// + /// + public string AgentName { get; set; } + + /// + /// Gets or sets the agent image uri + /// + /// + public string AgentImageUri { get; set; } + + /// + /// The verification key of the agent + /// + /// + public string AgentKey { get; set; } + + /// + /// Gets or sets the name of the pool. + /// + /// The name of the pool. + public string PoolName + { + get; + set; + } = "DefaultPool"; + + /// + /// Gets or sets the genesis filename. + /// + /// The genesis filename. + public string GenesisFilename + { + get; + set; + } + + /// + /// Gets or sets the protocol version of the nodes. + /// + /// + /// The protocol version. + /// + public int ProtocolVersion + { + get; + set; + } = 2; + + /// + /// Gets or sets the revocation registry URI path e.g. "/tails". + /// This path will be appended to the EndpointUri value. + /// This is used to optimize the ASP.NET Core middleware pipeline. + /// Default value is "/tails". The value must start with a slash '/'. + /// + /// + /// The revocation registry base URI path. + /// + public string RevocationRegistryUriPath { get; set; } = "/tails"; + + /// + /// Gets or sets the revocation registry directory where + /// revocation tails files will be stored. The default path + /// is ~/.indy_client/tails + /// + /// + /// The revocation registry directory. + /// + public string RevocationRegistryDirectory { get; set; } = EnvironmentUtils.GetTailsPath(); + + /// + /// Gets or sets the backup directory where physical backups will be stored. + /// This property is only used when running a mediator service. + /// + /// + /// The backup directory. + /// + public string BackupDirectory { get; set; } = Path.Combine(Path.GetTempPath(), "AriesBackups"); + + /// + /// Automatically respond to credential offers with a credential request. Default: false + /// + /// The name of the pool. + public bool AutoRespondCredentialOffer + { + get; + set; + } = false; + + /// + /// Automatically respond to credential request with corresponding credentials. Default: false + /// + /// The name of the pool. + public bool AutoRespondCredentialRequest + { + get; + set; + } = false; + + /// + /// Gets or sets the value for UseMessageTypesHttps. + /// Only affects messages created by the default services, + /// if you create additional messages you have to set the useMessageTypesHttps via ctor too + /// + /// True if to use UseMessageTypesHttps. + public bool UseMessageTypesHttps { get; set; } + + /// + /// Gets or sets the value for Metadata dictionary. + /// This dictionary can be used with InboxCreation on the mediator agent. + /// Data is stored under InboxRecord tags on the mediator agent. + /// + public Dictionary MetaData { get; set; } + } +} diff --git a/src/Hyperledger.Aries/Configuration/AriesFrameworkBuilder.cs b/legacy/src/Hyperledger.Aries/Configuration/AriesFrameworkBuilder.cs similarity index 100% rename from src/Hyperledger.Aries/Configuration/AriesFrameworkBuilder.cs rename to legacy/src/Hyperledger.Aries/Configuration/AriesFrameworkBuilder.cs diff --git a/src/Hyperledger.Aries/Configuration/DefaultProvisioningHostedService.cs b/legacy/src/Hyperledger.Aries/Configuration/DefaultProvisioningHostedService.cs similarity index 100% rename from src/Hyperledger.Aries/Configuration/DefaultProvisioningHostedService.cs rename to legacy/src/Hyperledger.Aries/Configuration/DefaultProvisioningHostedService.cs diff --git a/src/Hyperledger.Aries/Configuration/DefaultProvisioningService.cs b/legacy/src/Hyperledger.Aries/Configuration/DefaultProvisioningService.cs similarity index 100% rename from src/Hyperledger.Aries/Configuration/DefaultProvisioningService.cs rename to legacy/src/Hyperledger.Aries/Configuration/DefaultProvisioningService.cs diff --git a/src/Hyperledger.Aries/Configuration/IProvisioningService.cs b/legacy/src/Hyperledger.Aries/Configuration/IProvisioningService.cs similarity index 100% rename from src/Hyperledger.Aries/Configuration/IProvisioningService.cs rename to legacy/src/Hyperledger.Aries/Configuration/IProvisioningService.cs diff --git a/src/Hyperledger.Aries/Configuration/PoolConfigurationService.cs b/legacy/src/Hyperledger.Aries/Configuration/PoolConfigurationService.cs similarity index 100% rename from src/Hyperledger.Aries/Configuration/PoolConfigurationService.cs rename to legacy/src/Hyperledger.Aries/Configuration/PoolConfigurationService.cs diff --git a/src/Hyperledger.Aries/Configuration/ProvisioningRecord.cs b/legacy/src/Hyperledger.Aries/Configuration/ProvisioningRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Configuration/ProvisioningRecord.cs rename to legacy/src/Hyperledger.Aries/Configuration/ProvisioningRecord.cs diff --git a/src/Hyperledger.Aries/Configuration/ServiceCollectionExtensions.cs b/legacy/src/Hyperledger.Aries/Configuration/ServiceCollectionExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Configuration/ServiceCollectionExtensions.cs rename to legacy/src/Hyperledger.Aries/Configuration/ServiceCollectionExtensions.cs diff --git a/src/Hyperledger.Aries/Configuration/TxnAuthorAcceptanceService.cs b/legacy/src/Hyperledger.Aries/Configuration/TxnAuthorAcceptanceService.cs similarity index 99% rename from src/Hyperledger.Aries/Configuration/TxnAuthorAcceptanceService.cs rename to legacy/src/Hyperledger.Aries/Configuration/TxnAuthorAcceptanceService.cs index c9088d6e..bb0baf84 100644 --- a/src/Hyperledger.Aries/Configuration/TxnAuthorAcceptanceService.cs +++ b/legacy/src/Hyperledger.Aries/Configuration/TxnAuthorAcceptanceService.cs @@ -79,7 +79,7 @@ public Task StopAsync(CancellationToken cancellationToken) private string GetDigest(IndyTaa taa) { - using var shaAlgorithm = SHA256.Create(); + using var shaAlgorithm = SHA256.Create(); return shaAlgorithm.ComputeHash( $"{taa.Version}{taa.Text}" .GetUTF8Bytes()) diff --git a/src/Hyperledger.Aries/Decorators/Attachments/AttachDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Attachments/AttachDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/Attachments/AttachExtensions.cs b/legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Attachments/AttachExtensions.cs rename to legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachExtensions.cs diff --git a/src/Hyperledger.Aries/Decorators/Attachments/Attachment.cs b/legacy/src/Hyperledger.Aries/Decorators/Attachments/Attachment.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Attachments/Attachment.cs rename to legacy/src/Hyperledger.Aries/Decorators/Attachments/Attachment.cs diff --git a/src/Hyperledger.Aries/Decorators/Attachments/AttachmentContent.cs b/legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachmentContent.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Attachments/AttachmentContent.cs rename to legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachmentContent.cs diff --git a/src/Hyperledger.Aries/Decorators/Attachments/AttachmentContentExtensions.cs b/legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachmentContentExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Attachments/AttachmentContentExtensions.cs rename to legacy/src/Hyperledger.Aries/Decorators/Attachments/AttachmentContentExtensions.cs diff --git a/src/Hyperledger.Aries/Decorators/Attachments/JsonWebSignature.cs b/legacy/src/Hyperledger.Aries/Decorators/Attachments/JsonWebSignature.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Attachments/JsonWebSignature.cs rename to legacy/src/Hyperledger.Aries/Decorators/Attachments/JsonWebSignature.cs diff --git a/src/Hyperledger.Aries/Decorators/DecoratorExtensions.cs b/legacy/src/Hyperledger.Aries/Decorators/DecoratorExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/DecoratorExtensions.cs rename to legacy/src/Hyperledger.Aries/Decorators/DecoratorExtensions.cs diff --git a/src/Hyperledger.Aries/Decorators/Decorators.cs b/legacy/src/Hyperledger.Aries/Decorators/Decorators.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Decorators.cs rename to legacy/src/Hyperledger.Aries/Decorators/Decorators.cs diff --git a/src/Hyperledger.Aries/Decorators/Payments/PaymentReceiptDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/Payments/PaymentReceiptDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Payments/PaymentReceiptDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/Payments/PaymentReceiptDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/Payments/PaymentRequestDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/Payments/PaymentRequestDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Payments/PaymentRequestDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/Payments/PaymentRequestDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/PleaseAck/OnValues.cs b/legacy/src/Hyperledger.Aries/Decorators/PleaseAck/OnValues.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/PleaseAck/OnValues.cs rename to legacy/src/Hyperledger.Aries/Decorators/PleaseAck/OnValues.cs diff --git a/src/Hyperledger.Aries/Decorators/PleaseAck/PleaseAckDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/PleaseAck/PleaseAckDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/PleaseAck/PleaseAckDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/PleaseAck/PleaseAckDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/Service/ServiceDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/Service/ServiceDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Service/ServiceDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/Service/ServiceDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/Service/ServiceDecoratorExtensions.cs b/legacy/src/Hyperledger.Aries/Decorators/Service/ServiceDecoratorExtensions.cs similarity index 97% rename from src/Hyperledger.Aries/Decorators/Service/ServiceDecoratorExtensions.cs rename to legacy/src/Hyperledger.Aries/Decorators/Service/ServiceDecoratorExtensions.cs index 89a52227..1dd24442 100644 --- a/src/Hyperledger.Aries/Decorators/Service/ServiceDecoratorExtensions.cs +++ b/legacy/src/Hyperledger.Aries/Decorators/Service/ServiceDecoratorExtensions.cs @@ -1,29 +1,29 @@ -using System.Linq; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Decorators.Service; -using Hyperledger.Aries.Utils; - -namespace System -{ - /// - /// Service decorator extensions - /// - public static class ServiceDecoratorExtensions - { - /// - /// Get a service decorator representation for this provisioning record - /// - /// - /// - /// - public static ServiceDecorator ToServiceDecorator(this ProvisioningRecord record, bool useDidKeyFormat = false) - { - return new ServiceDecorator - { - ServiceEndpoint = record.Endpoint.Uri, - RoutingKeys = useDidKeyFormat ? record.Endpoint.Verkey.Select(DidUtils.ConvertVerkeyToDidKey) : record.Endpoint.Verkey, - RecipientKeys = new [] { useDidKeyFormat ? DidUtils.ConvertVerkeyToDidKey(record.IssuerVerkey) : record.IssuerVerkey } - }; - } - } -} +using System.Linq; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Decorators.Service; +using Hyperledger.Aries.Utils; + +namespace System +{ + /// + /// Service decorator extensions + /// + public static class ServiceDecoratorExtensions + { + /// + /// Get a service decorator representation for this provisioning record + /// + /// + /// + /// + public static ServiceDecorator ToServiceDecorator(this ProvisioningRecord record, bool useDidKeyFormat = false) + { + return new ServiceDecorator + { + ServiceEndpoint = record.Endpoint.Uri, + RoutingKeys = useDidKeyFormat ? record.Endpoint.Verkey.Select(DidUtils.ConvertVerkeyToDidKey) : record.Endpoint.Verkey, + RecipientKeys = new [] { useDidKeyFormat ? DidUtils.ConvertVerkeyToDidKey(record.IssuerVerkey) : record.IssuerVerkey } + }; + } + } +} diff --git a/src/Hyperledger.Aries/Decorators/Signature/SignatureDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/Signature/SignatureDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Signature/SignatureDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/Signature/SignatureDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/Signature/SignatureUtils.cs b/legacy/src/Hyperledger.Aries/Decorators/Signature/SignatureUtils.cs similarity index 99% rename from src/Hyperledger.Aries/Decorators/Signature/SignatureUtils.cs rename to legacy/src/Hyperledger.Aries/Decorators/Signature/SignatureUtils.cs index d0508caa..d9d4578d 100644 --- a/src/Hyperledger.Aries/Decorators/Signature/SignatureUtils.cs +++ b/legacy/src/Hyperledger.Aries/Decorators/Signature/SignatureUtils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Threading.Tasks; using Hyperledger.Aries.Agents; diff --git a/src/Hyperledger.Aries/Decorators/Threading/ThreadDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/Threading/ThreadDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Threading/ThreadDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/Threading/ThreadDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/Threading/ThreadDecoratorExtensions.cs b/legacy/src/Hyperledger.Aries/Decorators/Threading/ThreadDecoratorExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Threading/ThreadDecoratorExtensions.cs rename to legacy/src/Hyperledger.Aries/Decorators/Threading/ThreadDecoratorExtensions.cs diff --git a/src/Hyperledger.Aries/Decorators/Transport/TransportDecorator.cs b/legacy/src/Hyperledger.Aries/Decorators/Transport/TransportDecorator.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Transport/TransportDecorator.cs rename to legacy/src/Hyperledger.Aries/Decorators/Transport/TransportDecorator.cs diff --git a/src/Hyperledger.Aries/Decorators/Transport/TransportDecoratorExtensions.cs b/legacy/src/Hyperledger.Aries/Decorators/Transport/TransportDecoratorExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Decorators/Transport/TransportDecoratorExtensions.cs rename to legacy/src/Hyperledger.Aries/Decorators/Transport/TransportDecoratorExtensions.cs diff --git a/src/Hyperledger.Aries/Features/BasicMessage/BasicMessage.cs b/legacy/src/Hyperledger.Aries/Features/BasicMessage/BasicMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/BasicMessage/BasicMessage.cs rename to legacy/src/Hyperledger.Aries/Features/BasicMessage/BasicMessage.cs diff --git a/src/Hyperledger.Aries/Features/BasicMessage/BasicMessageRecord.cs b/legacy/src/Hyperledger.Aries/Features/BasicMessage/BasicMessageRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Features/BasicMessage/BasicMessageRecord.cs rename to legacy/src/Hyperledger.Aries/Features/BasicMessage/BasicMessageRecord.cs diff --git a/src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageHandler.cs b/legacy/src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageHandler.cs rename to legacy/src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageHandler.cs diff --git a/src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageService.cs b/legacy/src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageService.cs rename to legacy/src/Hyperledger.Aries/Features/BasicMessage/DefaultBasicMessageService.cs diff --git a/src/Hyperledger.Aries/Features/BasicMessage/IBasicMessageService.cs b/legacy/src/Hyperledger.Aries/Features/BasicMessage/IBasicMessageService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/BasicMessage/IBasicMessageService.cs rename to legacy/src/Hyperledger.Aries/Features/BasicMessage/IBasicMessageService.cs diff --git a/src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryHandler.cs b/legacy/src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryHandler.cs rename to legacy/src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryHandler.cs diff --git a/src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryService.cs b/legacy/src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryService.cs rename to legacy/src/Hyperledger.Aries/Features/Discovery/DefaultDiscoveryService.cs diff --git a/src/Hyperledger.Aries/Features/Discovery/DiscoveryDiscloseMessage.cs b/legacy/src/Hyperledger.Aries/Features/Discovery/DiscoveryDiscloseMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Discovery/DiscoveryDiscloseMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Discovery/DiscoveryDiscloseMessage.cs diff --git a/src/Hyperledger.Aries/Features/Discovery/DiscoveryQueryMessage.cs b/legacy/src/Hyperledger.Aries/Features/Discovery/DiscoveryQueryMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Discovery/DiscoveryQueryMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Discovery/DiscoveryQueryMessage.cs diff --git a/src/Hyperledger.Aries/Features/Discovery/IDiscoveryService.cs b/legacy/src/Hyperledger.Aries/Features/Discovery/IDiscoveryService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Discovery/IDiscoveryService.cs rename to legacy/src/Hyperledger.Aries/Features/Discovery/IDiscoveryService.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Connection.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Connection.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Connection.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Connection.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionAlias.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionAlias.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionAlias.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionAlias.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionRecord.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionRecord.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/ConnectionRecord.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidCommServiceEndpoint.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidCommServiceEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidCommServiceEndpoint.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidCommServiceEndpoint.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDoc.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDoc.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDoc.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDoc.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocExtensions.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocExtensions.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocExtensions.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocKey.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocKey.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocKey.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocKey.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointTypes.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointTypes.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointTypes.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointTypes.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointsConverter.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointsConverter.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointsConverter.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/DidDocServiceEndpointsConverter.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IDidDocServiceEndpoint.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IDidDocServiceEndpoint.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IDidDocServiceEndpoint.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IDidDocServiceEndpoint.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IndyAgentDidDocService.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IndyAgentDidDocService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IndyAgentDidDocService.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Common/Dids/IndyAgentDidDocService.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionHandler.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionHandler.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionHandler.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionService.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionService.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/DefaultConnectionService.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/Extensions/ConnectionServiceExtensions.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Extensions/ConnectionServiceExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/Extensions/ConnectionServiceExtensions.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Extensions/ConnectionServiceExtensions.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/IConnectionService.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/IConnectionService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/IConnectionService.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/IConnectionService.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionAcknowledgeMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionAcknowledgeMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionAcknowledgeMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionAcknowledgeMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionInvitationMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionInvitationMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionInvitationMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionInvitationMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionRequestMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionRequestMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionRequestMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionRequestMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionResponseMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionResponseMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionResponseMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/ConnectionResponseMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/InviteConfiguration.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/InviteConfiguration.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/Connection/Models/InviteConfiguration.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/Connection/Models/InviteConfiguration.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeHandler.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeHandler.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeHandler.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeService.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeService.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/DefaultDidExchangeService.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/DidExchange/IDidExchangeService.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/IDidExchangeService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/DidExchange/IDidExchangeService.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/IDidExchangeService.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeCompleteMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeCompleteMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeCompleteMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeCompleteMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeProblemReportMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeProblemReportMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeProblemReportMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeProblemReportMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeRequestMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeRequestMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeRequestMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeRequestMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeResponseMessage.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeResponseMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeResponseMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/DidExchange/Models/DidExchangeResponseMessage.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/HandshakeConstants.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/HandshakeConstants.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/HandshakeConstants.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/HandshakeConstants.cs diff --git a/src/Hyperledger.Aries/Features/Handshakes/HandshakeProtocol.cs b/legacy/src/Hyperledger.Aries/Features/Handshakes/HandshakeProtocol.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Handshakes/HandshakeProtocol.cs rename to legacy/src/Hyperledger.Aries/Features/Handshakes/HandshakeProtocol.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ICredentialService.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ICredentialService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ICredentialService.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ICredentialService.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ISchemaService.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ISchemaService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ISchemaService.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ISchemaService.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ITailsService.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ITailsService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ITailsService.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Abstractions/ITailsService.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/CredentialServiceExtensions.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/CredentialServiceExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/CredentialServiceExtensions.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/CredentialServiceExtensions.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialHandler.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialHandler.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialHandler.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialService.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialService.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultCredentialService.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/DefaultSchemaService.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultSchemaService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/DefaultSchemaService.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultSchemaService.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/DefaultTailsService.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultTailsService.cs similarity index 99% rename from src/Hyperledger.Aries/Features/IssueCredential/DefaultTailsService.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultTailsService.cs index 1778bfc8..a8d531d8 100644 --- a/src/Hyperledger.Aries/Features/IssueCredential/DefaultTailsService.cs +++ b/legacy/src/Hyperledger.Aries/Features/IssueCredential/DefaultTailsService.cs @@ -3,7 +3,7 @@ using System.IO; using System.Linq; using System.Net.Http; -using System.Security.Cryptography; +using System.Security.Cryptography; using System.Threading.Tasks; using Hyperledger.Aries.Agents; using Hyperledger.Aries.Configuration; @@ -13,7 +13,7 @@ using Hyperledger.Indy.BlobStorageApi; using Hyperledger.Indy.PoolApi; using Microsoft.Extensions.Options; -using Multiformats.Base; +using Multiformats.Base; using Newtonsoft.Json.Linq; namespace Hyperledger.Aries.Features.IssueCredential @@ -113,9 +113,9 @@ public virtual async Task EnsureTailsExistsAsync(IAgentContext agentCont using var sha256 = SHA256.Create(); var computedHash = sha256.ComputeHash(bytes); - if (!computedHash.SequenceEqual(hash)) - { - throw new Exception("Tails file hash didn't match"); + if (!computedHash.SequenceEqual(hash)) + { + throw new Exception("Tails file hash didn't match"); } File.WriteAllBytes( diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/Credential.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Credential.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/Credential.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Credential.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialDefinitionConfiguration.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialDefinitionConfiguration.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialDefinitionConfiguration.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialDefinitionConfiguration.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialInfo.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialInfo.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialInfo.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialInfo.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialMimeTypes.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialMimeTypes.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialMimeTypes.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialMimeTypes.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttribute.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttribute.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttribute.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttribute.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttributeConverter.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttributeConverter.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttributeConverter.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/CredentialPreviewAttributeConverter.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialAcknowledgeMessage.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialAcknowledgeMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialAcknowledgeMessage.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialAcknowledgeMessage.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialIssueMessage.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialIssueMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialIssueMessage.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialIssueMessage.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialOfferMessage.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialOfferMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialOfferMessage.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialOfferMessage.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialPreviewMessage.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialPreviewMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialPreviewMessage.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialPreviewMessage.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialProposalMessage.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialProposalMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialProposalMessage.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialProposalMessage.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialRequestMessage.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialRequestMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialRequestMessage.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/Messages/CredentialRequestMessage.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Models/OfferConfiguration.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/OfferConfiguration.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Models/OfferConfiguration.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Models/OfferConfiguration.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialRecord.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialRecord.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialRecord.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialState.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialState.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialState.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialState.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialTrigger.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialTrigger.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialTrigger.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/CredentialTrigger.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Records/DefinitionRecord.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/DefinitionRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Records/DefinitionRecord.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/DefinitionRecord.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Records/RevocationRegistryRecord.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/RevocationRegistryRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Records/RevocationRegistryRecord.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/RevocationRegistryRecord.cs diff --git a/src/Hyperledger.Aries/Features/IssueCredential/Records/SchemaRecord.cs b/legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/SchemaRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Features/IssueCredential/Records/SchemaRecord.cs rename to legacy/src/Hyperledger.Aries/Features/IssueCredential/Records/SchemaRecord.cs diff --git a/src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandHandler.cs b/legacy/src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandHandler.cs rename to legacy/src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandHandler.cs diff --git a/src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandService.cs b/legacy/src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandService.cs rename to legacy/src/Hyperledger.Aries/Features/OutOfBand/DefaultOutOfBandService.cs diff --git a/src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseAcceptedMessage.cs b/legacy/src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseAcceptedMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseAcceptedMessage.cs rename to legacy/src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseAcceptedMessage.cs diff --git a/src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseMessage.cs b/legacy/src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseMessage.cs rename to legacy/src/Hyperledger.Aries/Features/OutOfBand/HandshakeReuseMessage.cs diff --git a/src/Hyperledger.Aries/Features/OutOfBand/IOutOfBandService.cs b/legacy/src/Hyperledger.Aries/Features/OutOfBand/IOutOfBandService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/OutOfBand/IOutOfBandService.cs rename to legacy/src/Hyperledger.Aries/Features/OutOfBand/IOutOfBandService.cs diff --git a/src/Hyperledger.Aries/Features/OutOfBand/InvitationMessage.cs b/legacy/src/Hyperledger.Aries/Features/OutOfBand/InvitationMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/OutOfBand/InvitationMessage.cs rename to legacy/src/Hyperledger.Aries/Features/OutOfBand/InvitationMessage.cs diff --git a/src/Hyperledger.Aries/Features/OutOfBand/InvitationMessageExtensions.cs b/legacy/src/Hyperledger.Aries/Features/OutOfBand/InvitationMessageExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Features/OutOfBand/InvitationMessageExtensions.cs rename to legacy/src/Hyperledger.Aries/Features/OutOfBand/InvitationMessageExtensions.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/DefaultProofHandler.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/DefaultProofHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/DefaultProofHandler.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/DefaultProofHandler.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/DefaultProofService.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/DefaultProofService.cs similarity index 97% rename from src/Hyperledger.Aries/Features/PresentProof/DefaultProofService.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/DefaultProofService.cs index a40c7d0c..38447660 100644 --- a/src/Hyperledger.Aries/Features/PresentProof/DefaultProofService.cs +++ b/legacy/src/Hyperledger.Aries/Features/PresentProof/DefaultProofService.cs @@ -1,991 +1,991 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Common; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Contracts; -using Hyperledger.Aries.Decorators; -using Hyperledger.Aries.Decorators.Attachments; -using Hyperledger.Aries.Decorators.Service; -using Hyperledger.Aries.Decorators.Threading; -using Hyperledger.Aries.Extensions; -using Hyperledger.Aries.Features.Handshakes.Common; -using Hyperledger.Aries.Features.Handshakes.Connection; -using Hyperledger.Aries.Features.IssueCredential; -using Hyperledger.Aries.Features.PresentProof.Messages; -using Hyperledger.Aries.Ledger.Models; -using Hyperledger.Aries.Models.Events; -using Hyperledger.Aries.Storage; -using Hyperledger.Aries.Utils; -using Hyperledger.Indy.AnonCredsApi; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Hyperledger.Aries.Features.PresentProof -{ - /// - /// Proof Service - /// - /// - public class DefaultProofService : IProofService - { - /// - /// The event aggregator - /// - protected readonly IEventAggregator EventAggregator; - - /// - /// The connection service - /// - protected readonly IConnectionService ConnectionService; - - /// - /// The record service - /// - protected readonly IWalletRecordService RecordService; - - /// - /// The provisioning service - /// - protected readonly IProvisioningService ProvisioningService; - - /// - /// The ledger service - /// - protected readonly ILedgerService LedgerService; - - /// - /// The logger - /// - protected readonly ILogger Logger; - - /// - /// The tails service - /// - protected readonly ITailsService TailsService; - - /// - /// Message Service - /// - protected readonly IMessageService MessageService; - - /// - /// Initializes a new instance of the class. - /// - /// The event aggregator. - /// The connection service. - /// The record service. - /// The provisioning service. - /// The ledger service. - /// The tails service. - /// The message service. - /// The logger. - public DefaultProofService( - IEventAggregator eventAggregator, - IConnectionService connectionService, - IWalletRecordService recordService, - IProvisioningService provisioningService, - ILedgerService ledgerService, - ITailsService tailsService, - IMessageService messageService, - ILogger logger) - { - EventAggregator = eventAggregator; - TailsService = tailsService; - MessageService = messageService; - ConnectionService = connectionService; - RecordService = recordService; - ProvisioningService = provisioningService; - LedgerService = ledgerService; - Logger = logger; - } - - /// - public virtual async Task CreateProofAsync(IAgentContext agentContext, - ProofRequest proofRequest, RequestedCredentials requestedCredentials) - { - var provisioningRecord = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); - - var credentialObjects = new List(); - foreach (var credId in requestedCredentials.GetCredentialIdentifiers()) - { - var credentialInfo = JsonConvert.DeserializeObject( - await AnonCreds.ProverGetCredentialAsync(agentContext.Wallet, credId)); - - credentialObjects.Add(credentialInfo); - } - - var schemas = await BuildSchemasAsync( - agentContext: agentContext, - schemaIds: credentialObjects.Select(x => x.SchemaId).Distinct()); - - var definitions = await BuildCredentialDefinitionsAsync( - agentContext: agentContext, - credentialDefIds: credentialObjects.Select(x => x.CredentialDefinitionId).Distinct()); - - var revocationStates = await BuildRevocationStatesAsync( - agentContext: agentContext, - credentialObjects: credentialObjects, - proofRequest: proofRequest, - requestedCredentials: requestedCredentials); - - var proofJson = await AnonCreds.ProverCreateProofAsync( - wallet: agentContext.Wallet, - proofRequest: proofRequest.ToJson(), - requestedCredentials: requestedCredentials.ToJson(), - masterSecret: provisioningRecord.MasterSecretId, - schemas: schemas, - credentialDefs: definitions, - revStates: revocationStates); - - return proofJson; - } - - /// - public virtual async Task CreatePresentationAsync(IAgentContext agentContext, RequestPresentationMessage requestPresentation, RequestedCredentials requestedCredentials) - { - var service = requestPresentation.GetDecorator(DecoratorNames.ServiceDecorator); - - var record = await ProcessRequestAsync(agentContext, requestPresentation, null); - var (presentationMessage, proofRecord) = await CreatePresentationAsync(agentContext, record.Id, requestedCredentials); - - await MessageService.SendAsync( - agentContext: agentContext, - message: presentationMessage, - recipientKey: service.RecipientKeys.First(), - endpointUri: service.ServiceEndpoint, - routingKeys: service.RoutingKeys?.ToArray()); - - return proofRecord; - } - - /// - public virtual async Task RejectProofRequestAsync(IAgentContext agentContext, string proofRequestId) - { - var request = await GetAsync(agentContext, proofRequestId); - - if (request.State != ProofState.Requested) - throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, - $"Proof record state was invalid. Expected '{ProofState.Requested}', found '{request.State}'"); - - await request.TriggerAsync(ProofTrigger.Reject); - await RecordService.UpdateAsync(agentContext.Wallet, request); - } - - /// - public virtual async Task IsRevokedAsync(IAgentContext context, string credentialRecordId) - { - return await IsRevokedAsync(context, await RecordService.GetAsync(context.Wallet, credentialRecordId)); - } - - /// - public virtual async Task IsRevokedAsync(IAgentContext context, CredentialRecord record) - { - if (record.RevocationRegistryId == null) return false; - if (record.State == CredentialState.Offered || record.State == CredentialState.Requested) return false; - if (record.State == CredentialState.Revoked || record.State == CredentialState.Rejected) return true; - - var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - var proofRequest = new ProofRequest - { - Name = "revocation check", - Version = "1.0", - Nonce = await AnonCreds.GenerateNonceAsync(), - RequestedAttributes = new Dictionary - { - { "referent1", new ProofAttributeInfo { Name = record.CredentialAttributesValues.First().Name } } - }, NonRevoked = new RevocationInterval - { - From = (uint)now, - To = (uint)now - } - }; - - var proof = await CreateProofAsync(context, proofRequest, new RequestedCredentials - { - RequestedAttributes = new Dictionary - { - { "referent1", new RequestedAttribute { CredentialId = record.CredentialId, Timestamp = now, Revealed = true } } - } - }); - - var isValid = await VerifyProofAsync(context, proofRequest.ToJson(), proof); - - if (!isValid) - { - await record.TriggerAsync(CredentialTrigger.Revoke); - - record.SetTag("LastRevocationCheck", now.ToString()); - await RecordService.UpdateAsync(context.Wallet, record); - } - - return !isValid; - } - - /// - public virtual async Task VerifyProofAsync(IAgentContext agentContext, string proofRequestJson, string proofJson, bool validateEncoding = true) - { - var proof = JsonConvert.DeserializeObject(proofJson); - var proofRequest = proofRequestJson.ToObject(); - - // If any values are revealed, validate encoding - // against expected values - if (validateEncoding && proof.RequestedProof.RevealedAttributes != null) - foreach (var attribute in proof.RequestedProof.RevealedAttributes) - { - if (!CredentialUtils.CheckValidEncoding(attribute.Value.Raw, attribute.Value.Encoded)) - { - throw new AriesFrameworkException(ErrorCode.InvalidProofEncoding, - $"The encoded value for '{attribute.Key}' is invalid. " + - $"Expected '{CredentialUtils.GetEncoded(attribute.Value.Raw)}'. " + - $"Actual '{attribute.Value.Encoded}'"); - } - } - - var schemas = await BuildSchemasAsync(agentContext, - proof.Identifiers - .Select(x => x.SchemaId) - .Where(x => x != null) - .Distinct()); - - var definitions = await BuildCredentialDefinitionsAsync(agentContext, - proof.Identifiers - .Select(x => x.CredentialDefintionId) - .Where(x => x != null) - .Distinct()); - - var revocationDefinitions = await BuildRevocationRegistryDefinitionsAsync(agentContext, - proof.Identifiers - .Select(x => x.RevocationRegistryId) - .Where(x => x != null) - .Distinct()); - - var revocationRegistries = await BuildRevocationRegistriesAsync( - agentContext, - proof.Identifiers.Where(x => x.RevocationRegistryId != null)); - - return await AnonCreds.VerifierVerifyProofAsync( - proofRequestJson, - proofJson, - schemas, - definitions, - revocationDefinitions, - revocationRegistries); - } - - /// - public virtual async Task VerifyProofAsync(IAgentContext agentContext, string proofRecId) - { - var proofRecord = await GetAsync(agentContext, proofRecId); - - if (proofRecord.State != ProofState.Accepted) - throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, - $"Proof record state was invalid. Expected '{ProofState.Accepted}', found '{proofRecord.State}'"); - - return await VerifyProofAsync(agentContext, proofRecord.RequestJson, proofRecord.ProofJson); - } - - /// - public virtual Task> ListAsync(IAgentContext agentContext, ISearchQuery query = null, - int count = 100) => RecordService.SearchAsync(agentContext.Wallet, query, null, count); - - /// - public virtual async Task GetAsync(IAgentContext agentContext, string proofRecId) - { - Logger.LogInformation(LoggingEvents.GetProofRecord, "ProofRecordId {0}", proofRecId); - - return await RecordService.GetAsync(agentContext.Wallet, proofRecId) ?? - throw new AriesFrameworkException(ErrorCode.RecordNotFound, "Proof record not found"); - } - - /// - public virtual async Task> ListCredentialsForProofRequestAsync(IAgentContext agentContext, - ProofRequest proofRequest, string attributeReferent) - { - using (var search = - await AnonCreds.ProverSearchCredentialsForProofRequestAsync(agentContext.Wallet, proofRequest.ToJson())) - { - var searchResult = await search.NextAsync(attributeReferent, 100); - return JsonConvert.DeserializeObject>(searchResult); - } - } - - /// - public virtual async Task CreateAcknowledgeMessageAsync(IAgentContext agentContext, - string proofRecordId, string status = AcknowledgementStatusConstants.Ok) - { - var record = await GetAsync(agentContext, proofRecordId); - - var threadId = record.GetTag(TagConstants.LastThreadId); - var acknowledgeMessage = new PresentationAcknowledgeMessage(agentContext.UseMessageTypesHttps) - { - Id = threadId, - Status = status - }; - acknowledgeMessage.ThreadFrom(threadId); - - return acknowledgeMessage; - } - - /// - public virtual async Task ProcessAcknowledgeMessageAsync(IAgentContext agentContext, PresentationAcknowledgeMessage acknowledgeMessage) - { - var proofRecord = await this.GetByThreadIdAsync(agentContext, acknowledgeMessage.GetThreadId()); - - EventAggregator.Publish(new ServiceMessageProcessingEvent - { - RecordId = proofRecord.Id, - MessageType = acknowledgeMessage.Type, - ThreadId = acknowledgeMessage.GetThreadId() - }); - - return proofRecord; - } - - /// - public virtual async Task<(ProposePresentationMessage, ProofRecord)> CreateProposalAsync(IAgentContext agentContext, ProofProposal proofProposal, string connectionId) - { - Logger.LogInformation(LoggingEvents.CreateProofRequest, "ConnectionId {0}", connectionId); - - if (proofProposal == null) - { - throw new ArgumentNullException(nameof(proofProposal), "You must provide a presentation preview"); ; - } - if (connectionId != null) - { - var connection = await ConnectionService.GetAsync(agentContext, connectionId); - - if (connection.State != ConnectionState.Connected) - throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, - $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); - } - this.CheckProofProposalParameters(proofProposal); - - - var threadId = Guid.NewGuid().ToString(); - var proofRecord = new ProofRecord - { - Id = Guid.NewGuid().ToString(), - ConnectionId = connectionId, - ProposalJson = proofProposal.ToJson(), - State = ProofState.Proposed - }; - - proofRecord.SetTag(TagConstants.Role, TagConstants.Holder); - proofRecord.SetTag(TagConstants.LastThreadId, threadId); - - await RecordService.AddAsync(agentContext.Wallet, proofRecord); - - var message = new ProposePresentationMessage(agentContext.UseMessageTypesHttps) - { - Id = threadId, - Comment = proofProposal.Comment, - PresentationPreviewMessage = new PresentationPreviewMessage(agentContext.UseMessageTypesHttps) - { - ProposedAttributes = proofProposal.ProposedAttributes.ToArray(), - ProposedPredicates = proofProposal.ProposedPredicates.ToArray() - }, - }; - message.ThreadFrom(threadId); - return (message, proofRecord); - } - - public virtual async Task ProcessProposalAsync(IAgentContext agentContext, ProposePresentationMessage proposePresentationMessage, ConnectionRecord connection) - { - // save in wallet - - var proofProposal = new ProofProposal - { - Comment = proposePresentationMessage.Comment, - ProposedAttributes = proposePresentationMessage.PresentationPreviewMessage.ProposedAttributes.ToList(), - ProposedPredicates = proposePresentationMessage.PresentationPreviewMessage.ProposedPredicates.ToList() - }; - - var proofRecord = new ProofRecord - { - Id = Guid.NewGuid().ToString(), - ProposalJson = proofProposal.ToJson(), - ConnectionId = connection?.Id, - State = ProofState.Proposed - }; - - proofRecord.SetTag(TagConstants.LastThreadId, proposePresentationMessage.GetThreadId()); - proofRecord.SetTag(TagConstants.Role, TagConstants.Requestor); - await RecordService.AddAsync(agentContext.Wallet, proofRecord); - - EventAggregator.Publish(new ServiceMessageProcessingEvent - { - RecordId = proofRecord.Id, - MessageType = proposePresentationMessage.Type, - ThreadId = proposePresentationMessage.GetThreadId() - }); - - return proofRecord; - } - - /// - public virtual async Task<(RequestPresentationMessage, ProofRecord)> CreateRequestFromProposalAsync( - IAgentContext agentContext, ProofRequestParameters requestParams, string proofRecordId, string connectionId) - { - Logger.LogInformation(LoggingEvents.CreateProofRequest, "ConnectionId {0}", connectionId); - - if (proofRecordId == null) - { - throw new ArgumentNullException(nameof(proofRecordId), "You must provide proof record Id"); - } - if (connectionId != null) - { - var connection = await ConnectionService.GetAsync(agentContext, connectionId); - - if (connection.State != ConnectionState.Connected) - throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, - $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); - } - - var proofRecord = await RecordService.GetAsync(agentContext.Wallet, proofRecordId); - var proofProposal = proofRecord.ProposalJson.ToObject(); - - - // Build Proof Request from Proposal info - var proofRequest = new ProofRequest - { - Name = requestParams.Name, - Version = requestParams.Version, - Nonce = await AnonCreds.GenerateNonceAsync(), - RequestedAttributes = new Dictionary(), - NonRevoked = requestParams.NonRevoked - }; - - var attributesByReferent = new Dictionary>(); - foreach (var proposedAttribute in proofProposal.ProposedAttributes) - { - if (proposedAttribute.Referent == null) - { - proposedAttribute.Referent = Guid.NewGuid().ToString(); - } - - if (attributesByReferent.TryGetValue(proposedAttribute.Referent, out var referentAttributes)) - { - referentAttributes.Add(proposedAttribute); - } - else - { - attributesByReferent.Add(proposedAttribute.Referent, new List { proposedAttribute }); - } - } - - foreach (var referent in attributesByReferent.AsEnumerable()) - { - var proposedAttributes = referent.Value; - var attributeName = proposedAttributes.Count() == 1 ? proposedAttributes.Single().Name : null; - var attributeNames = proposedAttributes.Count() > 1 ? proposedAttributes.ConvertAll(r => r.Name).ToArray() : null; - - - var requestedAttribute = new ProofAttributeInfo() - { - Name = attributeName, - Names = attributeNames, - Restrictions = new List - { - new AttributeFilter { - CredentialDefinitionId = proposedAttributes.First().CredentialDefinitionId, - SchemaId = proposedAttributes.First().SchemaId, - IssuerDid = proposedAttributes.First().IssuerDid - } - } - }; - proofRequest.RequestedAttributes.Add(referent.Key, requestedAttribute); - Console.WriteLine($"Added Attribute to Proof Request \n {proofRequest.ToString()}"); - } - - foreach (var pred in proofProposal.ProposedPredicates) - { - if (pred.Referent == null) - { - pred.Referent = Guid.NewGuid().ToString(); - } - var predicate = new ProofPredicateInfo() - { - Name = pred.Name, - PredicateType = pred.Predicate, - PredicateValue = pred.Threshold, - Restrictions = new List - { - new AttributeFilter { - CredentialDefinitionId = pred.CredentialDefinitionId, - SchemaId = pred.SchemaId, - IssuerDid = pred.IssuerDid - } - } - - }; - proofRequest.RequestedPredicates.Add(pred.Referent, predicate); - } - - proofRecord.RequestJson = proofRequest.ToJson(); - await proofRecord.TriggerAsync(ProofTrigger.Request); - await RecordService.UpdateAsync(agentContext.Wallet, proofRecord); - - var message = new RequestPresentationMessage(agentContext.UseMessageTypesHttps) - { - Id = proofRecord.Id, - Requests = new[] - { - new Attachment - { - Id = "libindy-request-presentation-0", - MimeType = CredentialMimeTypes.ApplicationJsonMimeType, - Data = new AttachmentContent - { - Base64 = proofRequest - .ToJson() - .GetUTF8Bytes() - .ToBase64String() - } - } - } - }; - message.ThreadFrom(proofRecord.GetTag(TagConstants.LastThreadId)); - return (message, proofRecord); - } - - /// - public virtual Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync( - IAgentContext agentContext, - ProofRequest proofRequest, - string connectionId) => - CreateRequestAsync( - agentContext: agentContext, - proofRequestJson: proofRequest?.ToJson(), - connectionId: connectionId); - - /// - public virtual async Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, string proofRequestJson, string connectionId) - { - Logger.LogInformation(LoggingEvents.CreateProofRequest, "ConnectionId {0}", connectionId); - - if (proofRequestJson == null) - { - throw new ArgumentNullException(nameof(proofRequestJson), "You must provide proof request"); - } - if (connectionId != null) - { - var connection = await ConnectionService.GetAsync(agentContext, connectionId); - - if (connection.State != ConnectionState.Connected) - throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, - $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); - } - - var threadId = Guid.NewGuid().ToString(); - var proofRecord = new ProofRecord - { - Id = Guid.NewGuid().ToString(), - ConnectionId = connectionId, - RequestJson = proofRequestJson - }; - proofRecord.SetTag(TagConstants.Role, TagConstants.Requestor); - proofRecord.SetTag(TagConstants.LastThreadId, threadId); - await RecordService.AddAsync(agentContext.Wallet, proofRecord); - - var message = new RequestPresentationMessage(agentContext.UseMessageTypesHttps) - { - Id = threadId, - Requests = new[] - { - new Attachment - { - Id = "libindy-request-presentation-0", - MimeType = CredentialMimeTypes.ApplicationJsonMimeType, - Data = new AttachmentContent - { - Base64 = proofRequestJson - .GetUTF8Bytes() - .ToBase64String() - } - } - } - }; - message.ThreadFrom(threadId); - return (message, proofRecord); - } - - /// - public virtual async Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, ProofRequest proofRequest, bool useDidKeyFormat = false) - { - var (message, record) = await CreateRequestAsync(agentContext, proofRequest, null); - var provisioning = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); - - message.AddDecorator(provisioning.ToServiceDecorator(useDidKeyFormat), DecoratorNames.ServiceDecorator); - record.SetTag("RequestData", message.ToByteArray().ToBase64UrlString()); - - return (message, record); - } - - /// - public virtual async Task ProcessRequestAsync(IAgentContext agentContext, RequestPresentationMessage requestPresentationMessage, ConnectionRecord connection) - { - var requestAttachment = requestPresentationMessage.Requests.FirstOrDefault(x => x.Id == "libindy-request-presentation-0") - ?? throw new ArgumentException("Presentation request attachment not found."); - - var requestJson = requestAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String(); - - ProofRecord proofRecord = null; - - try - { - proofRecord = await this.GetByThreadIdAsync(agentContext, requestPresentationMessage.GetThreadId()); - } - catch (AriesFrameworkException e) - { - if (e.ErrorCode != ErrorCode.RecordNotFound) - { - throw; - } - } - - if (proofRecord is null) - { - proofRecord = new ProofRecord - { - Id = Guid.NewGuid().ToString(), - RequestJson = requestJson, - ConnectionId = connection?.Id, - State = ProofState.Requested - }; - proofRecord.SetTag(TagConstants.LastThreadId, requestPresentationMessage.GetThreadId()); - proofRecord.SetTag(TagConstants.Role, TagConstants.Holder); - await RecordService.AddAsync(agentContext.Wallet, proofRecord); - } - else - { - await proofRecord.TriggerAsync(ProofTrigger.Request); - proofRecord.RequestJson = requestJson; - await RecordService.UpdateAsync(agentContext.Wallet, proofRecord); - } - - EventAggregator.Publish(new ServiceMessageProcessingEvent - { - RecordId = proofRecord.Id, - MessageType = requestPresentationMessage.Type, - ThreadId = requestPresentationMessage.GetThreadId() - }); - - return proofRecord; - } - - /// - public virtual async Task ProcessPresentationAsync(IAgentContext agentContext, PresentationMessage presentationMessage) - { - var proofRecord = await this.GetByThreadIdAsync(agentContext, presentationMessage.GetThreadId()); - - var requestAttachment = presentationMessage.Presentations.FirstOrDefault(x => x.Id == "libindy-presentation-0") - ?? throw new ArgumentException("Presentation attachment not found."); - - var proofJson = requestAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String(); - - if (proofRecord.State != ProofState.Requested) - throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, - $"Proof state was invalid. Expected '{ProofState.Requested}', found '{proofRecord.State}'"); - - proofRecord.ProofJson = proofJson; - await proofRecord.TriggerAsync(ProofTrigger.Accept); - await RecordService.UpdateAsync(agentContext.Wallet, proofRecord); - - EventAggregator.Publish(new ServiceMessageProcessingEvent - { - RecordId = proofRecord.Id, - MessageType = presentationMessage.Type, - ThreadId = presentationMessage.GetThreadId() - }); - - return proofRecord; - } - - /// - public virtual Task CreatePresentationAsync(IAgentContext agentContext, ProofRequest proofRequest, RequestedCredentials requestedCredentials) => - CreateProofAsync(agentContext, proofRequest, requestedCredentials); - - /// - public virtual async Task<(PresentationMessage, ProofRecord)> CreatePresentationAsync(IAgentContext agentContext, string proofRecordId, RequestedCredentials requestedCredentials) - { - var record = await GetAsync(agentContext, proofRecordId); - - if (record.State != ProofState.Requested) - throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, - $"Proof state was invalid. Expected '{ProofState.Requested}', found '{record.State}'"); - var proofJson = await CreatePresentationAsync( - agentContext, - record.RequestJson.ToObject(), - requestedCredentials); - - record.ProofJson = proofJson; - await record.TriggerAsync(ProofTrigger.Accept); - await RecordService.UpdateAsync(agentContext.Wallet, record); - - var threadId = record.GetTag(TagConstants.LastThreadId); - - var proofMsg = new PresentationMessage(agentContext.UseMessageTypesHttps) - { - Id = Guid.NewGuid().ToString(), - Presentations = new[] - { - new Attachment - { - Id = "libindy-presentation-0", - MimeType = CredentialMimeTypes.ApplicationJsonMimeType, - Data = new AttachmentContent - { - Base64 = proofJson - .GetUTF8Bytes() - .ToBase64String() - } - } - } - }; - proofMsg.ThreadFrom(threadId); - - return (proofMsg, record); - } - - #region Private Methods - - private async Task BuildSchemasAsync(IAgentContext agentContext, IEnumerable schemaIds) - { - var result = new Dictionary(); - - foreach (var schemaId in schemaIds) - { - var ledgerSchema = await LedgerService.LookupSchemaAsync(agentContext, schemaId); - result.Add(schemaId, JObject.Parse(ledgerSchema.ObjectJson)); - } - - return result.ToJson(); - } - - private async Task BuildCredentialDefinitionsAsync(IAgentContext agentContext, IEnumerable credentialDefIds) - { - var result = new Dictionary(); - - foreach (var schemaId in credentialDefIds) - { - var ledgerDefinition = await LedgerService.LookupDefinitionAsync(agentContext, schemaId); - result.Add(schemaId, JObject.Parse(ledgerDefinition.ObjectJson)); - } - - return result.ToJson(); - } - - private bool HasNonRevokedOnAttributeLevel(ProofRequest proofRequest) - { - foreach (var proofRequestRequestedAttribute in proofRequest.RequestedAttributes) - if (proofRequestRequestedAttribute.Value.NonRevoked != null) - return true; - - foreach (var proofRequestRequestedPredicate in proofRequest.RequestedPredicates) - if (proofRequestRequestedPredicate.Value.NonRevoked != null) - return true; - - return false; - } - - private async Task<(ParseRegistryResponseResult, string)> BuildRevocationStateAsync( - IAgentContext agentContext, CredentialInfo credential, ParseResponseResult registryDefinition, - RevocationInterval nonRevoked) - { - var delta = await LedgerService.LookupRevocationRegistryDeltaAsync( - agentContext: agentContext, - revocationRegistryId: credential.RevocationRegistryId, - // Ledger will not return correct revocation state if the 'from' field - // is other than 0 - from: 0, //nonRevoked.From, - to: nonRevoked.To); - - var tailsFile = await TailsService.EnsureTailsExistsAsync(agentContext, credential.RevocationRegistryId); - var tailsReader = await TailsService.OpenTailsAsync(tailsFile); - - var state = await AnonCreds.CreateRevocationStateAsync( - blobStorageReader: tailsReader, - revRegDef: registryDefinition.ObjectJson, - revRegDelta: delta.ObjectJson, - timestamp: (long)delta.Timestamp, - credRevId: credential.CredentialRevocationId); - - return (delta, state); - } - - private async Task BuildRevocationStatesAsync(IAgentContext agentContext, - IEnumerable credentialObjects, - ProofRequest proofRequest, - RequestedCredentials requestedCredentials) - { - var allCredentials = new List(); - allCredentials.AddRange(requestedCredentials.RequestedAttributes.Values); - allCredentials.AddRange(requestedCredentials.RequestedPredicates.Values); - - var result = new Dictionary>(); - - if (proofRequest.NonRevoked == null && !HasNonRevokedOnAttributeLevel(proofRequest)) - return result.ToJson(); - - foreach (var requestedCredential in allCredentials) - { - // ReSharper disable once PossibleMultipleEnumeration - var credential = credentialObjects.First(x => x.Referent == requestedCredential.CredentialId); - if (credential.RevocationRegistryId == null) - continue; - - var registryDefinition = await LedgerService.LookupRevocationRegistryDefinitionAsync( - agentContext: agentContext, - registryId: credential.RevocationRegistryId); - - if (proofRequest.NonRevoked != null) - { - var (delta, state) = await BuildRevocationStateAsync( - agentContext, credential, registryDefinition, proofRequest.NonRevoked); - - if (!result.ContainsKey(credential.RevocationRegistryId)) - result.Add(credential.RevocationRegistryId, new Dictionary()); - - requestedCredential.Timestamp = (long) delta.Timestamp; - if (!result[credential.RevocationRegistryId].ContainsKey($"{delta.Timestamp}")) - result[credential.RevocationRegistryId].Add($"{delta.Timestamp}", JObject.Parse(state)); - - continue; - } - - foreach (var proofRequestRequestedAttribute in proofRequest.RequestedAttributes) - { - var revocationInterval = proofRequestRequestedAttribute.Value.NonRevoked; - if (revocationInterval == null) - continue; - - var (delta, state) = await BuildRevocationStateAsync( - agentContext, credential, registryDefinition, revocationInterval); - - if (!result.ContainsKey(credential.RevocationRegistryId)) - result.Add(credential.RevocationRegistryId, new Dictionary()); - - requestedCredential.Timestamp = (long) delta.Timestamp; - if (!result[credential.RevocationRegistryId].ContainsKey($"{delta.Timestamp}")) - result[credential.RevocationRegistryId].Add($"{delta.Timestamp}", JObject.Parse(state)); - } - - foreach (var proofRequestRequestedPredicate in proofRequest.RequestedPredicates) - { - var revocationInterval = proofRequestRequestedPredicate.Value.NonRevoked; - if (revocationInterval == null) - continue; - - var (delta, state) = await BuildRevocationStateAsync( - agentContext, credential, registryDefinition, revocationInterval); - - if (!result.ContainsKey(credential.RevocationRegistryId)) - result.Add(credential.RevocationRegistryId, new Dictionary()); - - requestedCredential.Timestamp = (long) delta.Timestamp; - if (!result[credential.RevocationRegistryId].ContainsKey($"{delta.Timestamp}")) - result[credential.RevocationRegistryId].Add($"{delta.Timestamp}", JObject.Parse(state)); - } - } - - return result.ToJson(); - } - - private async Task BuildRevocationRegistriesAsync( - IAgentContext agentContext, - IEnumerable proofIdentifiers) - { - var result = new Dictionary>(); - - foreach (var identifier in proofIdentifiers) - { - if (identifier.Timestamp == null) continue; - - var revocationRegistry = await LedgerService.LookupRevocationRegistryAsync( - agentContext, - identifier.RevocationRegistryId, - long.Parse(identifier.Timestamp)); - - result.Add(identifier.RevocationRegistryId, - new Dictionary - { - {identifier.Timestamp, JObject.Parse(revocationRegistry.ObjectJson)} - }); - } - - return result.ToJson(); - } - - private async Task BuildRevocationRegistryDefinitionsAsync(IAgentContext agentContext, - IEnumerable revocationRegistryIds) - { - var result = new Dictionary(); - - foreach (var revocationRegistryId in revocationRegistryIds) - { - var ledgerSchema = - await LedgerService.LookupRevocationRegistryDefinitionAsync(agentContext, revocationRegistryId); - result.Add(revocationRegistryId, JObject.Parse(ledgerSchema.ObjectJson)); - } - - return result.ToJson(); - } - - private void CheckProofProposalParameters(ProofProposal proofProposal) - { - if (proofProposal.ProposedAttributes.Count > 1) - { - var attrList = proofProposal.ProposedAttributes; - var referents = new Dictionary(); - - // Check if all attributes that share referent have same requirements - for (int i = 0; i < attrList.Count; i++) - { - var attr = attrList[i]; - if (referents.ContainsKey(attr.Referent)) - { - if(referents[attr.Referent].IssuerDid != attr.IssuerDid || - referents[attr.Referent].SchemaId != attr.SchemaId || - referents[attr.Referent].CredentialDefinitionId != attr.CredentialDefinitionId) - { - throw new AriesFrameworkException(ErrorCode.InvalidParameterFormat, "All attributes that share a referent must have identical requirements"); - } - else - { - continue; - } - } - else - { - referents.Add(attr.Referent, attr); - } - } - } - - if (proofProposal.ProposedPredicates.Count > 1) - { - var predList = proofProposal.ProposedPredicates; - var referents = new Dictionary(); - - for (int i = 0; i < predList.Count; i++) - { - var pred = predList[i]; - if (referents.ContainsKey(pred.Referent)) - { - throw new AriesFrameworkException(ErrorCode.InvalidParameterFormat, "Proposed Predicates must all have unique referents"); - } - else - { - referents.Add(pred.Referent, pred); - } - } - } - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Common; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Contracts; +using Hyperledger.Aries.Decorators; +using Hyperledger.Aries.Decorators.Attachments; +using Hyperledger.Aries.Decorators.Service; +using Hyperledger.Aries.Decorators.Threading; +using Hyperledger.Aries.Extensions; +using Hyperledger.Aries.Features.Handshakes.Common; +using Hyperledger.Aries.Features.Handshakes.Connection; +using Hyperledger.Aries.Features.IssueCredential; +using Hyperledger.Aries.Features.PresentProof.Messages; +using Hyperledger.Aries.Ledger.Models; +using Hyperledger.Aries.Models.Events; +using Hyperledger.Aries.Storage; +using Hyperledger.Aries.Utils; +using Hyperledger.Indy.AnonCredsApi; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Hyperledger.Aries.Features.PresentProof +{ + /// + /// Proof Service + /// + /// + public class DefaultProofService : IProofService + { + /// + /// The event aggregator + /// + protected readonly IEventAggregator EventAggregator; + + /// + /// The connection service + /// + protected readonly IConnectionService ConnectionService; + + /// + /// The record service + /// + protected readonly IWalletRecordService RecordService; + + /// + /// The provisioning service + /// + protected readonly IProvisioningService ProvisioningService; + + /// + /// The ledger service + /// + protected readonly ILedgerService LedgerService; + + /// + /// The logger + /// + protected readonly ILogger Logger; + + /// + /// The tails service + /// + protected readonly ITailsService TailsService; + + /// + /// Message Service + /// + protected readonly IMessageService MessageService; + + /// + /// Initializes a new instance of the class. + /// + /// The event aggregator. + /// The connection service. + /// The record service. + /// The provisioning service. + /// The ledger service. + /// The tails service. + /// The message service. + /// The logger. + public DefaultProofService( + IEventAggregator eventAggregator, + IConnectionService connectionService, + IWalletRecordService recordService, + IProvisioningService provisioningService, + ILedgerService ledgerService, + ITailsService tailsService, + IMessageService messageService, + ILogger logger) + { + EventAggregator = eventAggregator; + TailsService = tailsService; + MessageService = messageService; + ConnectionService = connectionService; + RecordService = recordService; + ProvisioningService = provisioningService; + LedgerService = ledgerService; + Logger = logger; + } + + /// + public virtual async Task CreateProofAsync(IAgentContext agentContext, + ProofRequest proofRequest, RequestedCredentials requestedCredentials) + { + var provisioningRecord = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); + + var credentialObjects = new List(); + foreach (var credId in requestedCredentials.GetCredentialIdentifiers()) + { + var credentialInfo = JsonConvert.DeserializeObject( + await AnonCreds.ProverGetCredentialAsync(agentContext.Wallet, credId)); + + credentialObjects.Add(credentialInfo); + } + + var schemas = await BuildSchemasAsync( + agentContext: agentContext, + schemaIds: credentialObjects.Select(x => x.SchemaId).Distinct()); + + var definitions = await BuildCredentialDefinitionsAsync( + agentContext: agentContext, + credentialDefIds: credentialObjects.Select(x => x.CredentialDefinitionId).Distinct()); + + var revocationStates = await BuildRevocationStatesAsync( + agentContext: agentContext, + credentialObjects: credentialObjects, + proofRequest: proofRequest, + requestedCredentials: requestedCredentials); + + var proofJson = await AnonCreds.ProverCreateProofAsync( + wallet: agentContext.Wallet, + proofRequest: proofRequest.ToJson(), + requestedCredentials: requestedCredentials.ToJson(), + masterSecret: provisioningRecord.MasterSecretId, + schemas: schemas, + credentialDefs: definitions, + revStates: revocationStates); + + return proofJson; + } + + /// + public virtual async Task CreatePresentationAsync(IAgentContext agentContext, RequestPresentationMessage requestPresentation, RequestedCredentials requestedCredentials) + { + var service = requestPresentation.GetDecorator(DecoratorNames.ServiceDecorator); + + var record = await ProcessRequestAsync(agentContext, requestPresentation, null); + var (presentationMessage, proofRecord) = await CreatePresentationAsync(agentContext, record.Id, requestedCredentials); + + await MessageService.SendAsync( + agentContext: agentContext, + message: presentationMessage, + recipientKey: service.RecipientKeys.First(), + endpointUri: service.ServiceEndpoint, + routingKeys: service.RoutingKeys?.ToArray()); + + return proofRecord; + } + + /// + public virtual async Task RejectProofRequestAsync(IAgentContext agentContext, string proofRequestId) + { + var request = await GetAsync(agentContext, proofRequestId); + + if (request.State != ProofState.Requested) + throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, + $"Proof record state was invalid. Expected '{ProofState.Requested}', found '{request.State}'"); + + await request.TriggerAsync(ProofTrigger.Reject); + await RecordService.UpdateAsync(agentContext.Wallet, request); + } + + /// + public virtual async Task IsRevokedAsync(IAgentContext context, string credentialRecordId) + { + return await IsRevokedAsync(context, await RecordService.GetAsync(context.Wallet, credentialRecordId)); + } + + /// + public virtual async Task IsRevokedAsync(IAgentContext context, CredentialRecord record) + { + if (record.RevocationRegistryId == null) return false; + if (record.State == CredentialState.Offered || record.State == CredentialState.Requested) return false; + if (record.State == CredentialState.Revoked || record.State == CredentialState.Rejected) return true; + + var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + var proofRequest = new ProofRequest + { + Name = "revocation check", + Version = "1.0", + Nonce = await AnonCreds.GenerateNonceAsync(), + RequestedAttributes = new Dictionary + { + { "referent1", new ProofAttributeInfo { Name = record.CredentialAttributesValues.First().Name } } + }, NonRevoked = new RevocationInterval + { + From = (uint)now, + To = (uint)now + } + }; + + var proof = await CreateProofAsync(context, proofRequest, new RequestedCredentials + { + RequestedAttributes = new Dictionary + { + { "referent1", new RequestedAttribute { CredentialId = record.CredentialId, Timestamp = now, Revealed = true } } + } + }); + + var isValid = await VerifyProofAsync(context, proofRequest.ToJson(), proof); + + if (!isValid) + { + await record.TriggerAsync(CredentialTrigger.Revoke); + + record.SetTag("LastRevocationCheck", now.ToString()); + await RecordService.UpdateAsync(context.Wallet, record); + } + + return !isValid; + } + + /// + public virtual async Task VerifyProofAsync(IAgentContext agentContext, string proofRequestJson, string proofJson, bool validateEncoding = true) + { + var proof = JsonConvert.DeserializeObject(proofJson); + var proofRequest = proofRequestJson.ToObject(); + + // If any values are revealed, validate encoding + // against expected values + if (validateEncoding && proof.RequestedProof.RevealedAttributes != null) + foreach (var attribute in proof.RequestedProof.RevealedAttributes) + { + if (!CredentialUtils.CheckValidEncoding(attribute.Value.Raw, attribute.Value.Encoded)) + { + throw new AriesFrameworkException(ErrorCode.InvalidProofEncoding, + $"The encoded value for '{attribute.Key}' is invalid. " + + $"Expected '{CredentialUtils.GetEncoded(attribute.Value.Raw)}'. " + + $"Actual '{attribute.Value.Encoded}'"); + } + } + + var schemas = await BuildSchemasAsync(agentContext, + proof.Identifiers + .Select(x => x.SchemaId) + .Where(x => x != null) + .Distinct()); + + var definitions = await BuildCredentialDefinitionsAsync(agentContext, + proof.Identifiers + .Select(x => x.CredentialDefintionId) + .Where(x => x != null) + .Distinct()); + + var revocationDefinitions = await BuildRevocationRegistryDefinitionsAsync(agentContext, + proof.Identifiers + .Select(x => x.RevocationRegistryId) + .Where(x => x != null) + .Distinct()); + + var revocationRegistries = await BuildRevocationRegistriesAsync( + agentContext, + proof.Identifiers.Where(x => x.RevocationRegistryId != null)); + + return await AnonCreds.VerifierVerifyProofAsync( + proofRequestJson, + proofJson, + schemas, + definitions, + revocationDefinitions, + revocationRegistries); + } + + /// + public virtual async Task VerifyProofAsync(IAgentContext agentContext, string proofRecId) + { + var proofRecord = await GetAsync(agentContext, proofRecId); + + if (proofRecord.State != ProofState.Accepted) + throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, + $"Proof record state was invalid. Expected '{ProofState.Accepted}', found '{proofRecord.State}'"); + + return await VerifyProofAsync(agentContext, proofRecord.RequestJson, proofRecord.ProofJson); + } + + /// + public virtual Task> ListAsync(IAgentContext agentContext, ISearchQuery query = null, + int count = 100) => RecordService.SearchAsync(agentContext.Wallet, query, null, count); + + /// + public virtual async Task GetAsync(IAgentContext agentContext, string proofRecId) + { + Logger.LogInformation(LoggingEvents.GetProofRecord, "ProofRecordId {0}", proofRecId); + + return await RecordService.GetAsync(agentContext.Wallet, proofRecId) ?? + throw new AriesFrameworkException(ErrorCode.RecordNotFound, "Proof record not found"); + } + + /// + public virtual async Task> ListCredentialsForProofRequestAsync(IAgentContext agentContext, + ProofRequest proofRequest, string attributeReferent) + { + using (var search = + await AnonCreds.ProverSearchCredentialsForProofRequestAsync(agentContext.Wallet, proofRequest.ToJson())) + { + var searchResult = await search.NextAsync(attributeReferent, 100); + return JsonConvert.DeserializeObject>(searchResult); + } + } + + /// + public virtual async Task CreateAcknowledgeMessageAsync(IAgentContext agentContext, + string proofRecordId, string status = AcknowledgementStatusConstants.Ok) + { + var record = await GetAsync(agentContext, proofRecordId); + + var threadId = record.GetTag(TagConstants.LastThreadId); + var acknowledgeMessage = new PresentationAcknowledgeMessage(agentContext.UseMessageTypesHttps) + { + Id = threadId, + Status = status + }; + acknowledgeMessage.ThreadFrom(threadId); + + return acknowledgeMessage; + } + + /// + public virtual async Task ProcessAcknowledgeMessageAsync(IAgentContext agentContext, PresentationAcknowledgeMessage acknowledgeMessage) + { + var proofRecord = await this.GetByThreadIdAsync(agentContext, acknowledgeMessage.GetThreadId()); + + EventAggregator.Publish(new ServiceMessageProcessingEvent + { + RecordId = proofRecord.Id, + MessageType = acknowledgeMessage.Type, + ThreadId = acknowledgeMessage.GetThreadId() + }); + + return proofRecord; + } + + /// + public virtual async Task<(ProposePresentationMessage, ProofRecord)> CreateProposalAsync(IAgentContext agentContext, ProofProposal proofProposal, string connectionId) + { + Logger.LogInformation(LoggingEvents.CreateProofRequest, "ConnectionId {0}", connectionId); + + if (proofProposal == null) + { + throw new ArgumentNullException(nameof(proofProposal), "You must provide a presentation preview"); ; + } + if (connectionId != null) + { + var connection = await ConnectionService.GetAsync(agentContext, connectionId); + + if (connection.State != ConnectionState.Connected) + throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, + $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); + } + this.CheckProofProposalParameters(proofProposal); + + + var threadId = Guid.NewGuid().ToString(); + var proofRecord = new ProofRecord + { + Id = Guid.NewGuid().ToString(), + ConnectionId = connectionId, + ProposalJson = proofProposal.ToJson(), + State = ProofState.Proposed + }; + + proofRecord.SetTag(TagConstants.Role, TagConstants.Holder); + proofRecord.SetTag(TagConstants.LastThreadId, threadId); + + await RecordService.AddAsync(agentContext.Wallet, proofRecord); + + var message = new ProposePresentationMessage(agentContext.UseMessageTypesHttps) + { + Id = threadId, + Comment = proofProposal.Comment, + PresentationPreviewMessage = new PresentationPreviewMessage(agentContext.UseMessageTypesHttps) + { + ProposedAttributes = proofProposal.ProposedAttributes.ToArray(), + ProposedPredicates = proofProposal.ProposedPredicates.ToArray() + }, + }; + message.ThreadFrom(threadId); + return (message, proofRecord); + } + + public virtual async Task ProcessProposalAsync(IAgentContext agentContext, ProposePresentationMessage proposePresentationMessage, ConnectionRecord connection) + { + // save in wallet + + var proofProposal = new ProofProposal + { + Comment = proposePresentationMessage.Comment, + ProposedAttributes = proposePresentationMessage.PresentationPreviewMessage.ProposedAttributes.ToList(), + ProposedPredicates = proposePresentationMessage.PresentationPreviewMessage.ProposedPredicates.ToList() + }; + + var proofRecord = new ProofRecord + { + Id = Guid.NewGuid().ToString(), + ProposalJson = proofProposal.ToJson(), + ConnectionId = connection?.Id, + State = ProofState.Proposed + }; + + proofRecord.SetTag(TagConstants.LastThreadId, proposePresentationMessage.GetThreadId()); + proofRecord.SetTag(TagConstants.Role, TagConstants.Requestor); + await RecordService.AddAsync(agentContext.Wallet, proofRecord); + + EventAggregator.Publish(new ServiceMessageProcessingEvent + { + RecordId = proofRecord.Id, + MessageType = proposePresentationMessage.Type, + ThreadId = proposePresentationMessage.GetThreadId() + }); + + return proofRecord; + } + + /// + public virtual async Task<(RequestPresentationMessage, ProofRecord)> CreateRequestFromProposalAsync( + IAgentContext agentContext, ProofRequestParameters requestParams, string proofRecordId, string connectionId) + { + Logger.LogInformation(LoggingEvents.CreateProofRequest, "ConnectionId {0}", connectionId); + + if (proofRecordId == null) + { + throw new ArgumentNullException(nameof(proofRecordId), "You must provide proof record Id"); + } + if (connectionId != null) + { + var connection = await ConnectionService.GetAsync(agentContext, connectionId); + + if (connection.State != ConnectionState.Connected) + throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, + $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); + } + + var proofRecord = await RecordService.GetAsync(agentContext.Wallet, proofRecordId); + var proofProposal = proofRecord.ProposalJson.ToObject(); + + + // Build Proof Request from Proposal info + var proofRequest = new ProofRequest + { + Name = requestParams.Name, + Version = requestParams.Version, + Nonce = await AnonCreds.GenerateNonceAsync(), + RequestedAttributes = new Dictionary(), + NonRevoked = requestParams.NonRevoked + }; + + var attributesByReferent = new Dictionary>(); + foreach (var proposedAttribute in proofProposal.ProposedAttributes) + { + if (proposedAttribute.Referent == null) + { + proposedAttribute.Referent = Guid.NewGuid().ToString(); + } + + if (attributesByReferent.TryGetValue(proposedAttribute.Referent, out var referentAttributes)) + { + referentAttributes.Add(proposedAttribute); + } + else + { + attributesByReferent.Add(proposedAttribute.Referent, new List { proposedAttribute }); + } + } + + foreach (var referent in attributesByReferent.AsEnumerable()) + { + var proposedAttributes = referent.Value; + var attributeName = proposedAttributes.Count() == 1 ? proposedAttributes.Single().Name : null; + var attributeNames = proposedAttributes.Count() > 1 ? proposedAttributes.ConvertAll(r => r.Name).ToArray() : null; + + + var requestedAttribute = new ProofAttributeInfo() + { + Name = attributeName, + Names = attributeNames, + Restrictions = new List + { + new AttributeFilter { + CredentialDefinitionId = proposedAttributes.First().CredentialDefinitionId, + SchemaId = proposedAttributes.First().SchemaId, + IssuerDid = proposedAttributes.First().IssuerDid + } + } + }; + proofRequest.RequestedAttributes.Add(referent.Key, requestedAttribute); + Console.WriteLine($"Added Attribute to Proof Request \n {proofRequest.ToString()}"); + } + + foreach (var pred in proofProposal.ProposedPredicates) + { + if (pred.Referent == null) + { + pred.Referent = Guid.NewGuid().ToString(); + } + var predicate = new ProofPredicateInfo() + { + Name = pred.Name, + PredicateType = pred.Predicate, + PredicateValue = pred.Threshold, + Restrictions = new List + { + new AttributeFilter { + CredentialDefinitionId = pred.CredentialDefinitionId, + SchemaId = pred.SchemaId, + IssuerDid = pred.IssuerDid + } + } + + }; + proofRequest.RequestedPredicates.Add(pred.Referent, predicate); + } + + proofRecord.RequestJson = proofRequest.ToJson(); + await proofRecord.TriggerAsync(ProofTrigger.Request); + await RecordService.UpdateAsync(agentContext.Wallet, proofRecord); + + var message = new RequestPresentationMessage(agentContext.UseMessageTypesHttps) + { + Id = proofRecord.Id, + Requests = new[] + { + new Attachment + { + Id = "libindy-request-presentation-0", + MimeType = CredentialMimeTypes.ApplicationJsonMimeType, + Data = new AttachmentContent + { + Base64 = proofRequest + .ToJson() + .GetUTF8Bytes() + .ToBase64String() + } + } + } + }; + message.ThreadFrom(proofRecord.GetTag(TagConstants.LastThreadId)); + return (message, proofRecord); + } + + /// + public virtual Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync( + IAgentContext agentContext, + ProofRequest proofRequest, + string connectionId) => + CreateRequestAsync( + agentContext: agentContext, + proofRequestJson: proofRequest?.ToJson(), + connectionId: connectionId); + + /// + public virtual async Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, string proofRequestJson, string connectionId) + { + Logger.LogInformation(LoggingEvents.CreateProofRequest, "ConnectionId {0}", connectionId); + + if (proofRequestJson == null) + { + throw new ArgumentNullException(nameof(proofRequestJson), "You must provide proof request"); + } + if (connectionId != null) + { + var connection = await ConnectionService.GetAsync(agentContext, connectionId); + + if (connection.State != ConnectionState.Connected) + throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, + $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); + } + + var threadId = Guid.NewGuid().ToString(); + var proofRecord = new ProofRecord + { + Id = Guid.NewGuid().ToString(), + ConnectionId = connectionId, + RequestJson = proofRequestJson + }; + proofRecord.SetTag(TagConstants.Role, TagConstants.Requestor); + proofRecord.SetTag(TagConstants.LastThreadId, threadId); + await RecordService.AddAsync(agentContext.Wallet, proofRecord); + + var message = new RequestPresentationMessage(agentContext.UseMessageTypesHttps) + { + Id = threadId, + Requests = new[] + { + new Attachment + { + Id = "libindy-request-presentation-0", + MimeType = CredentialMimeTypes.ApplicationJsonMimeType, + Data = new AttachmentContent + { + Base64 = proofRequestJson + .GetUTF8Bytes() + .ToBase64String() + } + } + } + }; + message.ThreadFrom(threadId); + return (message, proofRecord); + } + + /// + public virtual async Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, ProofRequest proofRequest, bool useDidKeyFormat = false) + { + var (message, record) = await CreateRequestAsync(agentContext, proofRequest, null); + var provisioning = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); + + message.AddDecorator(provisioning.ToServiceDecorator(useDidKeyFormat), DecoratorNames.ServiceDecorator); + record.SetTag("RequestData", message.ToByteArray().ToBase64UrlString()); + + return (message, record); + } + + /// + public virtual async Task ProcessRequestAsync(IAgentContext agentContext, RequestPresentationMessage requestPresentationMessage, ConnectionRecord connection) + { + var requestAttachment = requestPresentationMessage.Requests.FirstOrDefault(x => x.Id == "libindy-request-presentation-0") + ?? throw new ArgumentException("Presentation request attachment not found."); + + var requestJson = requestAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String(); + + ProofRecord proofRecord = null; + + try + { + proofRecord = await this.GetByThreadIdAsync(agentContext, requestPresentationMessage.GetThreadId()); + } + catch (AriesFrameworkException e) + { + if (e.ErrorCode != ErrorCode.RecordNotFound) + { + throw; + } + } + + if (proofRecord is null) + { + proofRecord = new ProofRecord + { + Id = Guid.NewGuid().ToString(), + RequestJson = requestJson, + ConnectionId = connection?.Id, + State = ProofState.Requested + }; + proofRecord.SetTag(TagConstants.LastThreadId, requestPresentationMessage.GetThreadId()); + proofRecord.SetTag(TagConstants.Role, TagConstants.Holder); + await RecordService.AddAsync(agentContext.Wallet, proofRecord); + } + else + { + await proofRecord.TriggerAsync(ProofTrigger.Request); + proofRecord.RequestJson = requestJson; + await RecordService.UpdateAsync(agentContext.Wallet, proofRecord); + } + + EventAggregator.Publish(new ServiceMessageProcessingEvent + { + RecordId = proofRecord.Id, + MessageType = requestPresentationMessage.Type, + ThreadId = requestPresentationMessage.GetThreadId() + }); + + return proofRecord; + } + + /// + public virtual async Task ProcessPresentationAsync(IAgentContext agentContext, PresentationMessage presentationMessage) + { + var proofRecord = await this.GetByThreadIdAsync(agentContext, presentationMessage.GetThreadId()); + + var requestAttachment = presentationMessage.Presentations.FirstOrDefault(x => x.Id == "libindy-presentation-0") + ?? throw new ArgumentException("Presentation attachment not found."); + + var proofJson = requestAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String(); + + if (proofRecord.State != ProofState.Requested) + throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, + $"Proof state was invalid. Expected '{ProofState.Requested}', found '{proofRecord.State}'"); + + proofRecord.ProofJson = proofJson; + await proofRecord.TriggerAsync(ProofTrigger.Accept); + await RecordService.UpdateAsync(agentContext.Wallet, proofRecord); + + EventAggregator.Publish(new ServiceMessageProcessingEvent + { + RecordId = proofRecord.Id, + MessageType = presentationMessage.Type, + ThreadId = presentationMessage.GetThreadId() + }); + + return proofRecord; + } + + /// + public virtual Task CreatePresentationAsync(IAgentContext agentContext, ProofRequest proofRequest, RequestedCredentials requestedCredentials) => + CreateProofAsync(agentContext, proofRequest, requestedCredentials); + + /// + public virtual async Task<(PresentationMessage, ProofRecord)> CreatePresentationAsync(IAgentContext agentContext, string proofRecordId, RequestedCredentials requestedCredentials) + { + var record = await GetAsync(agentContext, proofRecordId); + + if (record.State != ProofState.Requested) + throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, + $"Proof state was invalid. Expected '{ProofState.Requested}', found '{record.State}'"); + var proofJson = await CreatePresentationAsync( + agentContext, + record.RequestJson.ToObject(), + requestedCredentials); + + record.ProofJson = proofJson; + await record.TriggerAsync(ProofTrigger.Accept); + await RecordService.UpdateAsync(agentContext.Wallet, record); + + var threadId = record.GetTag(TagConstants.LastThreadId); + + var proofMsg = new PresentationMessage(agentContext.UseMessageTypesHttps) + { + Id = Guid.NewGuid().ToString(), + Presentations = new[] + { + new Attachment + { + Id = "libindy-presentation-0", + MimeType = CredentialMimeTypes.ApplicationJsonMimeType, + Data = new AttachmentContent + { + Base64 = proofJson + .GetUTF8Bytes() + .ToBase64String() + } + } + } + }; + proofMsg.ThreadFrom(threadId); + + return (proofMsg, record); + } + + #region Private Methods + + private async Task BuildSchemasAsync(IAgentContext agentContext, IEnumerable schemaIds) + { + var result = new Dictionary(); + + foreach (var schemaId in schemaIds) + { + var ledgerSchema = await LedgerService.LookupSchemaAsync(agentContext, schemaId); + result.Add(schemaId, JObject.Parse(ledgerSchema.ObjectJson)); + } + + return result.ToJson(); + } + + private async Task BuildCredentialDefinitionsAsync(IAgentContext agentContext, IEnumerable credentialDefIds) + { + var result = new Dictionary(); + + foreach (var schemaId in credentialDefIds) + { + var ledgerDefinition = await LedgerService.LookupDefinitionAsync(agentContext, schemaId); + result.Add(schemaId, JObject.Parse(ledgerDefinition.ObjectJson)); + } + + return result.ToJson(); + } + + private bool HasNonRevokedOnAttributeLevel(ProofRequest proofRequest) + { + foreach (var proofRequestRequestedAttribute in proofRequest.RequestedAttributes) + if (proofRequestRequestedAttribute.Value.NonRevoked != null) + return true; + + foreach (var proofRequestRequestedPredicate in proofRequest.RequestedPredicates) + if (proofRequestRequestedPredicate.Value.NonRevoked != null) + return true; + + return false; + } + + private async Task<(ParseRegistryResponseResult, string)> BuildRevocationStateAsync( + IAgentContext agentContext, CredentialInfo credential, ParseResponseResult registryDefinition, + RevocationInterval nonRevoked) + { + var delta = await LedgerService.LookupRevocationRegistryDeltaAsync( + agentContext: agentContext, + revocationRegistryId: credential.RevocationRegistryId, + // Ledger will not return correct revocation state if the 'from' field + // is other than 0 + from: 0, //nonRevoked.From, + to: nonRevoked.To); + + var tailsFile = await TailsService.EnsureTailsExistsAsync(agentContext, credential.RevocationRegistryId); + var tailsReader = await TailsService.OpenTailsAsync(tailsFile); + + var state = await AnonCreds.CreateRevocationStateAsync( + blobStorageReader: tailsReader, + revRegDef: registryDefinition.ObjectJson, + revRegDelta: delta.ObjectJson, + timestamp: (long)delta.Timestamp, + credRevId: credential.CredentialRevocationId); + + return (delta, state); + } + + private async Task BuildRevocationStatesAsync(IAgentContext agentContext, + IEnumerable credentialObjects, + ProofRequest proofRequest, + RequestedCredentials requestedCredentials) + { + var allCredentials = new List(); + allCredentials.AddRange(requestedCredentials.RequestedAttributes.Values); + allCredentials.AddRange(requestedCredentials.RequestedPredicates.Values); + + var result = new Dictionary>(); + + if (proofRequest.NonRevoked == null && !HasNonRevokedOnAttributeLevel(proofRequest)) + return result.ToJson(); + + foreach (var requestedCredential in allCredentials) + { + // ReSharper disable once PossibleMultipleEnumeration + var credential = credentialObjects.First(x => x.Referent == requestedCredential.CredentialId); + if (credential.RevocationRegistryId == null) + continue; + + var registryDefinition = await LedgerService.LookupRevocationRegistryDefinitionAsync( + agentContext: agentContext, + registryId: credential.RevocationRegistryId); + + if (proofRequest.NonRevoked != null) + { + var (delta, state) = await BuildRevocationStateAsync( + agentContext, credential, registryDefinition, proofRequest.NonRevoked); + + if (!result.ContainsKey(credential.RevocationRegistryId)) + result.Add(credential.RevocationRegistryId, new Dictionary()); + + requestedCredential.Timestamp = (long) delta.Timestamp; + if (!result[credential.RevocationRegistryId].ContainsKey($"{delta.Timestamp}")) + result[credential.RevocationRegistryId].Add($"{delta.Timestamp}", JObject.Parse(state)); + + continue; + } + + foreach (var proofRequestRequestedAttribute in proofRequest.RequestedAttributes) + { + var revocationInterval = proofRequestRequestedAttribute.Value.NonRevoked; + if (revocationInterval == null) + continue; + + var (delta, state) = await BuildRevocationStateAsync( + agentContext, credential, registryDefinition, revocationInterval); + + if (!result.ContainsKey(credential.RevocationRegistryId)) + result.Add(credential.RevocationRegistryId, new Dictionary()); + + requestedCredential.Timestamp = (long) delta.Timestamp; + if (!result[credential.RevocationRegistryId].ContainsKey($"{delta.Timestamp}")) + result[credential.RevocationRegistryId].Add($"{delta.Timestamp}", JObject.Parse(state)); + } + + foreach (var proofRequestRequestedPredicate in proofRequest.RequestedPredicates) + { + var revocationInterval = proofRequestRequestedPredicate.Value.NonRevoked; + if (revocationInterval == null) + continue; + + var (delta, state) = await BuildRevocationStateAsync( + agentContext, credential, registryDefinition, revocationInterval); + + if (!result.ContainsKey(credential.RevocationRegistryId)) + result.Add(credential.RevocationRegistryId, new Dictionary()); + + requestedCredential.Timestamp = (long) delta.Timestamp; + if (!result[credential.RevocationRegistryId].ContainsKey($"{delta.Timestamp}")) + result[credential.RevocationRegistryId].Add($"{delta.Timestamp}", JObject.Parse(state)); + } + } + + return result.ToJson(); + } + + private async Task BuildRevocationRegistriesAsync( + IAgentContext agentContext, + IEnumerable proofIdentifiers) + { + var result = new Dictionary>(); + + foreach (var identifier in proofIdentifiers) + { + if (identifier.Timestamp == null) continue; + + var revocationRegistry = await LedgerService.LookupRevocationRegistryAsync( + agentContext, + identifier.RevocationRegistryId, + long.Parse(identifier.Timestamp)); + + result.Add(identifier.RevocationRegistryId, + new Dictionary + { + {identifier.Timestamp, JObject.Parse(revocationRegistry.ObjectJson)} + }); + } + + return result.ToJson(); + } + + private async Task BuildRevocationRegistryDefinitionsAsync(IAgentContext agentContext, + IEnumerable revocationRegistryIds) + { + var result = new Dictionary(); + + foreach (var revocationRegistryId in revocationRegistryIds) + { + var ledgerSchema = + await LedgerService.LookupRevocationRegistryDefinitionAsync(agentContext, revocationRegistryId); + result.Add(revocationRegistryId, JObject.Parse(ledgerSchema.ObjectJson)); + } + + return result.ToJson(); + } + + private void CheckProofProposalParameters(ProofProposal proofProposal) + { + if (proofProposal.ProposedAttributes.Count > 1) + { + var attrList = proofProposal.ProposedAttributes; + var referents = new Dictionary(); + + // Check if all attributes that share referent have same requirements + for (int i = 0; i < attrList.Count; i++) + { + var attr = attrList[i]; + if (referents.ContainsKey(attr.Referent)) + { + if(referents[attr.Referent].IssuerDid != attr.IssuerDid || + referents[attr.Referent].SchemaId != attr.SchemaId || + referents[attr.Referent].CredentialDefinitionId != attr.CredentialDefinitionId) + { + throw new AriesFrameworkException(ErrorCode.InvalidParameterFormat, "All attributes that share a referent must have identical requirements"); + } + else + { + continue; + } + } + else + { + referents.Add(attr.Referent, attr); + } + } + } + + if (proofProposal.ProposedPredicates.Count > 1) + { + var predList = proofProposal.ProposedPredicates; + var referents = new Dictionary(); + + for (int i = 0; i < predList.Count; i++) + { + var pred = predList[i]; + if (referents.ContainsKey(pred.Referent)) + { + throw new AriesFrameworkException(ErrorCode.InvalidParameterFormat, "Proposed Predicates must all have unique referents"); + } + else + { + referents.Add(pred.Referent, pred); + } + } + } + } + + #endregion + } +} diff --git a/src/Hyperledger.Aries/Features/PresentProof/IProofService.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/IProofService.cs similarity index 98% rename from src/Hyperledger.Aries/Features/PresentProof/IProofService.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/IProofService.cs index 656081e1..e2d12a95 100644 --- a/src/Hyperledger.Aries/Features/PresentProof/IProofService.cs +++ b/legacy/src/Hyperledger.Aries/Features/PresentProof/IProofService.cs @@ -1,247 +1,247 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Common; -using Hyperledger.Aries.Features.Handshakes.Common; -using Hyperledger.Aries.Features.IssueCredential; -using Hyperledger.Aries.Features.PresentProof.Messages; -using Hyperledger.Aries.Storage; - -namespace Hyperledger.Aries.Features.PresentProof -{ - /// - /// Proof Service. - /// - public interface IProofService - { - /// - /// Creates a proof proposal. - /// - /// The proof proposal. - /// Agent Context. - /// The proof proposal that will be created - /// Connection identifier of who the proof request will be sent to. - /// Proof Request message and identifier. - Task<(ProposePresentationMessage, ProofRecord)> CreateProposalAsync(IAgentContext agentContext, - ProofProposal proofProposal, string connectionId); - - - /// - /// Creates a proof request from a proof proposal. - /// - /// The proof request. - /// Agent Context. - /// The parameters requested to be proven - /// proposal Id - /// Connection identifier of who the proof proposal will be sent to. - /// Proof Request message and identifier. - Task<(RequestPresentationMessage, ProofRecord)> CreateRequestFromProposalAsync(IAgentContext agentContext, ProofRequestParameters requestParameters, - string proofRecordId, string connectionId); - - - /// - /// Processes a proof proposal and stores it for a given connection. - /// - /// The identifier for the stored proof proposal. - /// Agent Context. - /// A proof proposal. - /// Connection. - /// Proof identifier. - Task ProcessProposalAsync(IAgentContext agentContext, ProposePresentationMessage proposePresentationMessage, ConnectionRecord connection); - - - /// - /// Creates a proof request. - /// - /// The proof request. - /// Agent Context. - /// An enumeration of attribute we wish the prover to disclose. - /// Connection identifier of who the proof request will be sent to. - /// Proof Request message and identifier. - Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, - ProofRequest proofRequest, string connectionId); - - /// - /// Creates a new and associated - /// for use with connectionless transport. - /// - /// - /// - /// - /// - Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, ProofRequest proofRequest, bool useDidKeyFormat = false); - - /// - /// Creates a proof request. - /// - /// The proof request. - /// Agent Context. - /// A string representation of proof request json object - /// Connection identifier of who the proof request will be sent to. - /// Proof Request message and identifier. - Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, - string proofRequestJson, string connectionId); - - /// - /// Processes a proof request and stores it for a given connection. - /// - /// The identifier for the stored proof request. - /// Agent Context. - /// A proof request. - /// Connection. - /// Proof identifier. - Task ProcessRequestAsync(IAgentContext agentContext, RequestPresentationMessage proofRequest, ConnectionRecord connection); - - /// - /// Processes a proof and stores it for a given connection. - /// - /// The identifier for the stored proof. - /// Agent Context. - /// A proof. - /// Proof identifier. - Task ProcessPresentationAsync(IAgentContext agentContext, PresentationMessage proof); - - /// - /// Processes a proof request and generates an accompanying proof. - /// - /// Agent Context. - /// Proof Request. - /// Requested Credentials. - /// - /// The proof. - /// - Task CreatePresentationAsync( - IAgentContext agentContext, - ProofRequest proofRequest, - RequestedCredentials requestedCredentials); - - /// - /// Creates a presentation message based on a request over connectionless transport. - /// - /// - /// - /// - /// - Task CreatePresentationAsync(IAgentContext agentContext, RequestPresentationMessage requestPresentation, RequestedCredentials requestedCredentials); - - /// - /// Creates a proof. - /// - /// Agent Context. - /// Identifier of the proof request. - /// The requested credentials. - /// - /// The proof. - /// - Task<(PresentationMessage, ProofRecord)> CreatePresentationAsync(IAgentContext agentContext, - string proofRecordId, RequestedCredentials requestedCredentials); - - /// - /// Rejects a proof request. - /// - /// The proof. - /// Agent Context. - /// Identifier of the proof request. - Task RejectProofRequestAsync(IAgentContext agentContext, string proofRecordId); - - /// - /// Verifies a proof. - /// - /// Agent Context. - /// Identifier of the proof record. - /// Status indicating validity of proof. - Task VerifyProofAsync(IAgentContext agentContext, string proofRecordId); - - /// - /// Check if a credential has been revoked by validating against the revocation state - /// on the ledger. - /// - /// - /// This method can be used as a holder, to check if a credential thay own has been - /// revoked by the issuer. If a credential doesn't support revocation, this method will - /// always return false - /// - /// - /// - /// - Task IsRevokedAsync(IAgentContext context, CredentialRecord record); - - /// - /// Check if a credential has been revoked by validating against the revocation state - /// on the ledger. - /// - /// - /// This method can be used as a holder, to check if a credential thay own has been - /// revoked by the issuer. If a credential doesn't support revocation, this method will - /// always return false - /// - /// - /// - /// - Task IsRevokedAsync(IAgentContext context, string credentialRecordId); - - /// - /// Verifies a proof. - /// - /// Agent Context. - /// The proof request. - /// The proof. - /// - /// If true, validate the encoded raw values against standard encoding. - /// It is recommended to enable encoding validation to detect raw value tampering. - /// - /// Status indiciating the validity of proof. - Task VerifyProofAsync(IAgentContext agentContext, string proofRequestJson, string proofJson, bool validateEncoding = true); - - /// - /// Gets an enumeration of proofs stored in the wallet. - /// - /// Agent Context. - /// The query. - /// The count. - /// - /// A list of proofs. - /// - Task> ListAsync(IAgentContext agentContext, ISearchQuery query = null, int count = 100); - - /// - /// Gets a particular proof stored in the wallet. - /// - /// Agent Context. - /// Identifier of the proof record. - /// The proof. - Task GetAsync(IAgentContext agentContext, string proofRecId); - - /// - /// Lists the credentials available for the given proof request. - /// - /// Agent Context. - /// The proof request object. - /// The attribute referent. - /// - /// A collection of that are available - /// for building a proof for the given proof request - /// - Task> ListCredentialsForProofRequestAsync( - IAgentContext agentContext, - ProofRequest proofRequest, - string attributeReferent); - - /// - /// Creates a presentation acknowledge message async. - /// - /// Agent Context. - /// The ID of the proof record that is used. - /// The status of the acknowledgement message - /// The Presentation Acknowledgement Message. - Task CreateAcknowledgeMessageAsync(IAgentContext agentContext, string proofRecordId, string status = AcknowledgementStatusConstants.Ok); - - /// - /// Processes a presentation acknowledge message async. - /// - /// Agent Context. - /// The presentation acknowledgement message. - /// The proof record associated with the acknowledge message. - Task ProcessAcknowledgeMessageAsync(IAgentContext agentContext, PresentationAcknowledgeMessage presentationAcknowledgeMessage); - } -} +using System.Collections.Generic; +using System.Threading.Tasks; +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Common; +using Hyperledger.Aries.Features.Handshakes.Common; +using Hyperledger.Aries.Features.IssueCredential; +using Hyperledger.Aries.Features.PresentProof.Messages; +using Hyperledger.Aries.Storage; + +namespace Hyperledger.Aries.Features.PresentProof +{ + /// + /// Proof Service. + /// + public interface IProofService + { + /// + /// Creates a proof proposal. + /// + /// The proof proposal. + /// Agent Context. + /// The proof proposal that will be created + /// Connection identifier of who the proof request will be sent to. + /// Proof Request message and identifier. + Task<(ProposePresentationMessage, ProofRecord)> CreateProposalAsync(IAgentContext agentContext, + ProofProposal proofProposal, string connectionId); + + + /// + /// Creates a proof request from a proof proposal. + /// + /// The proof request. + /// Agent Context. + /// The parameters requested to be proven + /// proposal Id + /// Connection identifier of who the proof proposal will be sent to. + /// Proof Request message and identifier. + Task<(RequestPresentationMessage, ProofRecord)> CreateRequestFromProposalAsync(IAgentContext agentContext, ProofRequestParameters requestParameters, + string proofRecordId, string connectionId); + + + /// + /// Processes a proof proposal and stores it for a given connection. + /// + /// The identifier for the stored proof proposal. + /// Agent Context. + /// A proof proposal. + /// Connection. + /// Proof identifier. + Task ProcessProposalAsync(IAgentContext agentContext, ProposePresentationMessage proposePresentationMessage, ConnectionRecord connection); + + + /// + /// Creates a proof request. + /// + /// The proof request. + /// Agent Context. + /// An enumeration of attribute we wish the prover to disclose. + /// Connection identifier of who the proof request will be sent to. + /// Proof Request message and identifier. + Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, + ProofRequest proofRequest, string connectionId); + + /// + /// Creates a new and associated + /// for use with connectionless transport. + /// + /// + /// + /// + /// + Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, ProofRequest proofRequest, bool useDidKeyFormat = false); + + /// + /// Creates a proof request. + /// + /// The proof request. + /// Agent Context. + /// A string representation of proof request json object + /// Connection identifier of who the proof request will be sent to. + /// Proof Request message and identifier. + Task<(RequestPresentationMessage, ProofRecord)> CreateRequestAsync(IAgentContext agentContext, + string proofRequestJson, string connectionId); + + /// + /// Processes a proof request and stores it for a given connection. + /// + /// The identifier for the stored proof request. + /// Agent Context. + /// A proof request. + /// Connection. + /// Proof identifier. + Task ProcessRequestAsync(IAgentContext agentContext, RequestPresentationMessage proofRequest, ConnectionRecord connection); + + /// + /// Processes a proof and stores it for a given connection. + /// + /// The identifier for the stored proof. + /// Agent Context. + /// A proof. + /// Proof identifier. + Task ProcessPresentationAsync(IAgentContext agentContext, PresentationMessage proof); + + /// + /// Processes a proof request and generates an accompanying proof. + /// + /// Agent Context. + /// Proof Request. + /// Requested Credentials. + /// + /// The proof. + /// + Task CreatePresentationAsync( + IAgentContext agentContext, + ProofRequest proofRequest, + RequestedCredentials requestedCredentials); + + /// + /// Creates a presentation message based on a request over connectionless transport. + /// + /// + /// + /// + /// + Task CreatePresentationAsync(IAgentContext agentContext, RequestPresentationMessage requestPresentation, RequestedCredentials requestedCredentials); + + /// + /// Creates a proof. + /// + /// Agent Context. + /// Identifier of the proof request. + /// The requested credentials. + /// + /// The proof. + /// + Task<(PresentationMessage, ProofRecord)> CreatePresentationAsync(IAgentContext agentContext, + string proofRecordId, RequestedCredentials requestedCredentials); + + /// + /// Rejects a proof request. + /// + /// The proof. + /// Agent Context. + /// Identifier of the proof request. + Task RejectProofRequestAsync(IAgentContext agentContext, string proofRecordId); + + /// + /// Verifies a proof. + /// + /// Agent Context. + /// Identifier of the proof record. + /// Status indicating validity of proof. + Task VerifyProofAsync(IAgentContext agentContext, string proofRecordId); + + /// + /// Check if a credential has been revoked by validating against the revocation state + /// on the ledger. + /// + /// + /// This method can be used as a holder, to check if a credential thay own has been + /// revoked by the issuer. If a credential doesn't support revocation, this method will + /// always return false + /// + /// + /// + /// + Task IsRevokedAsync(IAgentContext context, CredentialRecord record); + + /// + /// Check if a credential has been revoked by validating against the revocation state + /// on the ledger. + /// + /// + /// This method can be used as a holder, to check if a credential thay own has been + /// revoked by the issuer. If a credential doesn't support revocation, this method will + /// always return false + /// + /// + /// + /// + Task IsRevokedAsync(IAgentContext context, string credentialRecordId); + + /// + /// Verifies a proof. + /// + /// Agent Context. + /// The proof request. + /// The proof. + /// + /// If true, validate the encoded raw values against standard encoding. + /// It is recommended to enable encoding validation to detect raw value tampering. + /// + /// Status indiciating the validity of proof. + Task VerifyProofAsync(IAgentContext agentContext, string proofRequestJson, string proofJson, bool validateEncoding = true); + + /// + /// Gets an enumeration of proofs stored in the wallet. + /// + /// Agent Context. + /// The query. + /// The count. + /// + /// A list of proofs. + /// + Task> ListAsync(IAgentContext agentContext, ISearchQuery query = null, int count = 100); + + /// + /// Gets a particular proof stored in the wallet. + /// + /// Agent Context. + /// Identifier of the proof record. + /// The proof. + Task GetAsync(IAgentContext agentContext, string proofRecId); + + /// + /// Lists the credentials available for the given proof request. + /// + /// Agent Context. + /// The proof request object. + /// The attribute referent. + /// + /// A collection of that are available + /// for building a proof for the given proof request + /// + Task> ListCredentialsForProofRequestAsync( + IAgentContext agentContext, + ProofRequest proofRequest, + string attributeReferent); + + /// + /// Creates a presentation acknowledge message async. + /// + /// Agent Context. + /// The ID of the proof record that is used. + /// The status of the acknowledgement message + /// The Presentation Acknowledgement Message. + Task CreateAcknowledgeMessageAsync(IAgentContext agentContext, string proofRecordId, string status = AcknowledgementStatusConstants.Ok); + + /// + /// Processes a presentation acknowledge message async. + /// + /// Agent Context. + /// The presentation acknowledgement message. + /// The proof record associated with the acknowledge message. + Task ProcessAcknowledgeMessageAsync(IAgentContext agentContext, PresentationAcknowledgeMessage presentationAcknowledgeMessage); + } +} diff --git a/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationAcknowledgeMessage.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationAcknowledgeMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationAcknowledgeMessage.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationAcknowledgeMessage.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationMessage.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationMessage.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationMessage.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationPreviewMessage.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationPreviewMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationPreviewMessage.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/PresentationPreviewMessage.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Messages/ProposePresentationMessage.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/ProposePresentationMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Messages/ProposePresentationMessage.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/ProposePresentationMessage.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Messages/RequestPresentationMessage.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/RequestPresentationMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Messages/RequestPresentationMessage.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Messages/RequestPresentationMessage.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/AttributeFilterConverter.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/AttributeFilterConverter.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/AttributeFilterConverter.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/AttributeFilterConverter.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/PartialProof.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/PartialProof.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/PartialProof.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/PartialProof.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttribute.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttribute.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttribute.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttribute.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttributeInfo.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttributeInfo.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttributeInfo.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofAttributeInfo.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofIdentifier.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofIdentifier.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofIdentifier.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofIdentifier.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofPredicateInfo.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofPredicateInfo.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofPredicateInfo.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofPredicateInfo.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofProposal.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofProposal.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofProposal.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofProposal.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequest.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequest.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequest.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequest.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestConfiguration.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestConfiguration.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestConfiguration.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestConfiguration.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestParameters.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestParameters.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestParameters.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/ProofRequestParameters.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedAttribute.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedAttribute.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/RequestedAttribute.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedAttribute.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedCredentials.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedCredentials.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/RequestedCredentials.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedCredentials.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedProof.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedProof.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/RequestedProof.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RequestedProof.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/Models/RevocationInterval.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RevocationInterval.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/Models/RevocationInterval.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/Models/RevocationInterval.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/ProofRecord.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/ProofRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/ProofRecord.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/ProofRecord.cs diff --git a/src/Hyperledger.Aries/Features/PresentProof/ProofServiceExtensions.cs b/legacy/src/Hyperledger.Aries/Features/PresentProof/ProofServiceExtensions.cs similarity index 100% rename from src/Hyperledger.Aries/Features/PresentProof/ProofServiceExtensions.cs rename to legacy/src/Hyperledger.Aries/Features/PresentProof/ProofServiceExtensions.cs diff --git a/src/Hyperledger.Aries/Features/ProblemReport/ProblemImpact.cs b/legacy/src/Hyperledger.Aries/Features/ProblemReport/ProblemImpact.cs similarity index 100% rename from src/Hyperledger.Aries/Features/ProblemReport/ProblemImpact.cs rename to legacy/src/Hyperledger.Aries/Features/ProblemReport/ProblemImpact.cs diff --git a/src/Hyperledger.Aries/Features/ProblemReport/ProblemReportMessage.cs b/legacy/src/Hyperledger.Aries/Features/ProblemReport/ProblemReportMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/ProblemReport/ProblemReportMessage.cs rename to legacy/src/Hyperledger.Aries/Features/ProblemReport/ProblemReportMessage.cs diff --git a/src/Hyperledger.Aries/Features/ProblemReport/RetryParty.cs b/legacy/src/Hyperledger.Aries/Features/ProblemReport/RetryParty.cs similarity index 100% rename from src/Hyperledger.Aries/Features/ProblemReport/RetryParty.cs rename to legacy/src/Hyperledger.Aries/Features/ProblemReport/RetryParty.cs diff --git a/src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationHandler.cs b/legacy/src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationHandler.cs rename to legacy/src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationHandler.cs diff --git a/src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationService.cs b/legacy/src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationService.cs rename to legacy/src/Hyperledger.Aries/Features/RevocationNotification/DefaultRevocationNotificationService.cs diff --git a/src/Hyperledger.Aries/Features/RevocationNotification/IRevocationNotificationService.cs b/legacy/src/Hyperledger.Aries/Features/RevocationNotification/IRevocationNotificationService.cs similarity index 100% rename from src/Hyperledger.Aries/Features/RevocationNotification/IRevocationNotificationService.cs rename to legacy/src/Hyperledger.Aries/Features/RevocationNotification/IRevocationNotificationService.cs diff --git a/src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationAcknowledgeMessage.cs b/legacy/src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationAcknowledgeMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationAcknowledgeMessage.cs rename to legacy/src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationAcknowledgeMessage.cs diff --git a/src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationMessage.cs b/legacy/src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationMessage.cs rename to legacy/src/Hyperledger.Aries/Features/RevocationNotification/RevocationNotificationMessage.cs diff --git a/src/Hyperledger.Aries/Features/Routing/DefaultForwardHandler.cs b/legacy/src/Hyperledger.Aries/Features/Routing/DefaultForwardHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Routing/DefaultForwardHandler.cs rename to legacy/src/Hyperledger.Aries/Features/Routing/DefaultForwardHandler.cs diff --git a/src/Hyperledger.Aries/Features/Routing/ForwardMessage.cs b/legacy/src/Hyperledger.Aries/Features/Routing/ForwardMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/Routing/ForwardMessage.cs rename to legacy/src/Hyperledger.Aries/Features/Routing/ForwardMessage.cs diff --git a/src/Hyperledger.Aries/Features/TrustPing/DefaultTrustPingHandler.cs b/legacy/src/Hyperledger.Aries/Features/TrustPing/DefaultTrustPingHandler.cs similarity index 100% rename from src/Hyperledger.Aries/Features/TrustPing/DefaultTrustPingHandler.cs rename to legacy/src/Hyperledger.Aries/Features/TrustPing/DefaultTrustPingHandler.cs diff --git a/src/Hyperledger.Aries/Features/TrustPing/TrustPingMessage.cs b/legacy/src/Hyperledger.Aries/Features/TrustPing/TrustPingMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/TrustPing/TrustPingMessage.cs rename to legacy/src/Hyperledger.Aries/Features/TrustPing/TrustPingMessage.cs diff --git a/src/Hyperledger.Aries/Features/TrustPing/TrustPingResponseMessage.cs b/legacy/src/Hyperledger.Aries/Features/TrustPing/TrustPingResponseMessage.cs similarity index 100% rename from src/Hyperledger.Aries/Features/TrustPing/TrustPingResponseMessage.cs rename to legacy/src/Hyperledger.Aries/Features/TrustPing/TrustPingResponseMessage.cs diff --git a/src/Hyperledger.Aries/Hyperledger.Aries.csproj b/legacy/src/Hyperledger.Aries/Hyperledger.Aries.csproj similarity index 95% rename from src/Hyperledger.Aries/Hyperledger.Aries.csproj rename to legacy/src/Hyperledger.Aries/Hyperledger.Aries.csproj index b56d1af1..8db5486a 100644 --- a/src/Hyperledger.Aries/Hyperledger.Aries.csproj +++ b/legacy/src/Hyperledger.Aries/Hyperledger.Aries.csproj @@ -6,6 +6,8 @@ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb enable 9.0 + false + netstandard2.1 diff --git a/src/Hyperledger.Aries/IsExternalInit.cs b/legacy/src/Hyperledger.Aries/IsExternalInit.cs similarity index 100% rename from src/Hyperledger.Aries/IsExternalInit.cs rename to legacy/src/Hyperledger.Aries/IsExternalInit.cs diff --git a/src/Hyperledger.Aries/Ledger/Abstractions/ILedgerService.cs b/legacy/src/Hyperledger.Aries/Ledger/Abstractions/ILedgerService.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Abstractions/ILedgerService.cs rename to legacy/src/Hyperledger.Aries/Ledger/Abstractions/ILedgerService.cs diff --git a/src/Hyperledger.Aries/Ledger/Abstractions/ILedgerSigningService.cs b/legacy/src/Hyperledger.Aries/Ledger/Abstractions/ILedgerSigningService.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Abstractions/ILedgerSigningService.cs rename to legacy/src/Hyperledger.Aries/Ledger/Abstractions/ILedgerSigningService.cs diff --git a/src/Hyperledger.Aries/Ledger/Abstractions/IPoolService.cs b/legacy/src/Hyperledger.Aries/Ledger/Abstractions/IPoolService.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Abstractions/IPoolService.cs rename to legacy/src/Hyperledger.Aries/Ledger/Abstractions/IPoolService.cs diff --git a/src/Hyperledger.Aries/Ledger/DefaultLedgerService.cs b/legacy/src/Hyperledger.Aries/Ledger/DefaultLedgerService.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/DefaultLedgerService.cs rename to legacy/src/Hyperledger.Aries/Ledger/DefaultLedgerService.cs diff --git a/src/Hyperledger.Aries/Ledger/DefaultLedgerSigningService.cs b/legacy/src/Hyperledger.Aries/Ledger/DefaultLedgerSigningService.cs similarity index 97% rename from src/Hyperledger.Aries/Ledger/DefaultLedgerSigningService.cs rename to legacy/src/Hyperledger.Aries/Ledger/DefaultLedgerSigningService.cs index a5f6690a..6750042e 100644 --- a/src/Hyperledger.Aries/Ledger/DefaultLedgerSigningService.cs +++ b/legacy/src/Hyperledger.Aries/Ledger/DefaultLedgerSigningService.cs @@ -1,46 +1,46 @@ -using System; -using System.Threading.Tasks; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Contracts; -using Hyperledger.Indy.WalletApi; -using IndyLedger = Hyperledger.Indy.LedgerApi.Ledger; - -namespace Hyperledger.Aries.Ledger -{ - /// - public class DefaultLedgerSigningService : ILedgerSigningService - { - private readonly IProvisioningService provisioningService; - - public DefaultLedgerSigningService(IProvisioningService provisioningService) - { - this.provisioningService = provisioningService; - } - /// - public virtual async Task SignRequestAsync(IAgentContext context, string submitterDid, string requestJson) - { - try - { - var provisioning = await provisioningService.GetProvisioningAsync(context.Wallet); - - if (provisioning?.TaaAcceptance != null) - { - requestJson = await IndyLedger.AppendTxnAuthorAgreementAcceptanceToRequestAsync(requestJson, provisioning.TaaAcceptance.Text, - provisioning.TaaAcceptance.Version, provisioning.TaaAcceptance.Digest, provisioning.TaaAcceptance.AcceptanceMechanism, (ulong)DateTimeOffset.Now.ToUnixTimeSeconds()); - } - } - catch (AriesFrameworkException ex) when (ex.ErrorCode == ErrorCode.RecordNotFound) - { - // OK, used in unit tests and scenarios when we want to simply send ledger commands - } - return await SignRequestAsync(context.Wallet, submitterDid, requestJson); - } - - /// - public virtual Task SignRequestAsync(Wallet wallet, string submitterDid, string requestJson) - { - return IndyLedger.SignRequestAsync(wallet, submitterDid, requestJson); - } - } -} +using System; +using System.Threading.Tasks; +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Contracts; +using Hyperledger.Indy.WalletApi; +using IndyLedger = Hyperledger.Indy.LedgerApi.Ledger; + +namespace Hyperledger.Aries.Ledger +{ + /// + public class DefaultLedgerSigningService : ILedgerSigningService + { + private readonly IProvisioningService provisioningService; + + public DefaultLedgerSigningService(IProvisioningService provisioningService) + { + this.provisioningService = provisioningService; + } + /// + public virtual async Task SignRequestAsync(IAgentContext context, string submitterDid, string requestJson) + { + try + { + var provisioning = await provisioningService.GetProvisioningAsync(context.Wallet); + + if (provisioning?.TaaAcceptance != null) + { + requestJson = await IndyLedger.AppendTxnAuthorAgreementAcceptanceToRequestAsync(requestJson, provisioning.TaaAcceptance.Text, + provisioning.TaaAcceptance.Version, provisioning.TaaAcceptance.Digest, provisioning.TaaAcceptance.AcceptanceMechanism, (ulong)DateTimeOffset.Now.ToUnixTimeSeconds()); + } + } + catch (AriesFrameworkException ex) when (ex.ErrorCode == ErrorCode.RecordNotFound) + { + // OK, used in unit tests and scenarios when we want to simply send ledger commands + } + return await SignRequestAsync(context.Wallet, submitterDid, requestJson); + } + + /// + public virtual Task SignRequestAsync(Wallet wallet, string submitterDid, string requestJson) + { + return IndyLedger.SignRequestAsync(wallet, submitterDid, requestJson); + } + } +} diff --git a/src/Hyperledger.Aries/Ledger/DefaultPoolService.cs b/legacy/src/Hyperledger.Aries/Ledger/DefaultPoolService.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/DefaultPoolService.cs rename to legacy/src/Hyperledger.Aries/Ledger/DefaultPoolService.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/AuthorizationConstraint.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/AuthorizationConstraint.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/AuthorizationConstraint.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/AuthorizationConstraint.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/AuthorizationRule.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/AuthorizationRule.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/AuthorizationRule.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/AuthorizationRule.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/ConstraintMetadata.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/ConstraintMetadata.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/ConstraintMetadata.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/ConstraintMetadata.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/CredDefId.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/CredDefId.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/CredDefId.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/CredDefId.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/IndyAml.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/IndyAml.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/IndyAml.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/IndyAml.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/IndyTaa.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/IndyTaa.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/IndyTaa.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/IndyTaa.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/IndyTaaAcceptance.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/IndyTaaAcceptance.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/IndyTaaAcceptance.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/IndyTaaAcceptance.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/ParseRegistryResponseResult.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/ParseRegistryResponseResult.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/ParseRegistryResponseResult.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/ParseRegistryResponseResult.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/ParseResponseResult.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/ParseResponseResult.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/ParseResponseResult.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/ParseResponseResult.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/PoolAwaitable.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/PoolAwaitable.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/PoolAwaitable.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/PoolAwaitable.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/SchemaId.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/SchemaId.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/SchemaId.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/SchemaId.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/ServiceEndpointResult.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/ServiceEndpointResult.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/ServiceEndpointResult.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/ServiceEndpointResult.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/TransactionActions.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/TransactionActions.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/TransactionActions.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/TransactionActions.cs diff --git a/src/Hyperledger.Aries/Ledger/Models/TransactionTypes.cs b/legacy/src/Hyperledger.Aries/Ledger/Models/TransactionTypes.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/Models/TransactionTypes.cs rename to legacy/src/Hyperledger.Aries/Ledger/Models/TransactionTypes.cs diff --git a/src/Hyperledger.Aries/Ledger/V2/DefaultLedgerServiceV2.cs b/legacy/src/Hyperledger.Aries/Ledger/V2/DefaultLedgerServiceV2.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/V2/DefaultLedgerServiceV2.cs rename to legacy/src/Hyperledger.Aries/Ledger/V2/DefaultLedgerServiceV2.cs diff --git a/src/Hyperledger.Aries/Ledger/V2/DefaultPoolServiceV2.cs b/legacy/src/Hyperledger.Aries/Ledger/V2/DefaultPoolServiceV2.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/V2/DefaultPoolServiceV2.cs rename to legacy/src/Hyperledger.Aries/Ledger/V2/DefaultPoolServiceV2.cs diff --git a/src/Hyperledger.Aries/Ledger/V2/ResponseParser.cs b/legacy/src/Hyperledger.Aries/Ledger/V2/ResponseParser.cs similarity index 100% rename from src/Hyperledger.Aries/Ledger/V2/ResponseParser.cs rename to legacy/src/Hyperledger.Aries/Ledger/V2/ResponseParser.cs diff --git a/src/Hyperledger.Aries/Payments/DefaultPaymentService.cs b/legacy/src/Hyperledger.Aries/Payments/DefaultPaymentService.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/DefaultPaymentService.cs rename to legacy/src/Hyperledger.Aries/Payments/DefaultPaymentService.cs diff --git a/src/Hyperledger.Aries/Payments/IPaymentService.cs b/legacy/src/Hyperledger.Aries/Payments/IPaymentService.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/IPaymentService.cs rename to legacy/src/Hyperledger.Aries/Payments/IPaymentService.cs diff --git a/src/Hyperledger.Aries/Payments/Models/AddressOptions.cs b/legacy/src/Hyperledger.Aries/Payments/Models/AddressOptions.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/AddressOptions.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/AddressOptions.cs diff --git a/src/Hyperledger.Aries/Payments/Models/IndyPaymentInputSource.cs b/legacy/src/Hyperledger.Aries/Payments/Models/IndyPaymentInputSource.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/IndyPaymentInputSource.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/IndyPaymentInputSource.cs diff --git a/src/Hyperledger.Aries/Payments/Models/IndyPaymentOutputSource.cs b/legacy/src/Hyperledger.Aries/Payments/Models/IndyPaymentOutputSource.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/IndyPaymentOutputSource.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/IndyPaymentOutputSource.cs diff --git a/src/Hyperledger.Aries/Payments/Models/PaymentAmount.cs b/legacy/src/Hyperledger.Aries/Payments/Models/PaymentAmount.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/PaymentAmount.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/PaymentAmount.cs diff --git a/src/Hyperledger.Aries/Payments/Models/PaymentDetails.cs b/legacy/src/Hyperledger.Aries/Payments/Models/PaymentDetails.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/PaymentDetails.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/PaymentDetails.cs diff --git a/src/Hyperledger.Aries/Payments/Models/PaymentItem.cs b/legacy/src/Hyperledger.Aries/Payments/Models/PaymentItem.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/PaymentItem.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/PaymentItem.cs diff --git a/src/Hyperledger.Aries/Payments/Models/PaymentMethod.cs b/legacy/src/Hyperledger.Aries/Payments/Models/PaymentMethod.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/PaymentMethod.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/PaymentMethod.cs diff --git a/src/Hyperledger.Aries/Payments/Models/PaymentMethodData.cs b/legacy/src/Hyperledger.Aries/Payments/Models/PaymentMethodData.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/PaymentMethodData.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/PaymentMethodData.cs diff --git a/src/Hyperledger.Aries/Payments/Models/TransactionCost.cs b/legacy/src/Hyperledger.Aries/Payments/Models/TransactionCost.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/Models/TransactionCost.cs rename to legacy/src/Hyperledger.Aries/Payments/Models/TransactionCost.cs diff --git a/src/Hyperledger.Aries/Payments/PaymentAddressRecord.cs b/legacy/src/Hyperledger.Aries/Payments/PaymentAddressRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/PaymentAddressRecord.cs rename to legacy/src/Hyperledger.Aries/Payments/PaymentAddressRecord.cs diff --git a/src/Hyperledger.Aries/Payments/PaymentRecord.cs b/legacy/src/Hyperledger.Aries/Payments/PaymentRecord.cs similarity index 100% rename from src/Hyperledger.Aries/Payments/PaymentRecord.cs rename to legacy/src/Hyperledger.Aries/Payments/PaymentRecord.cs diff --git a/src/Hyperledger.Aries/Properties/AssemblyInfo.cs b/legacy/src/Hyperledger.Aries/Properties/AssemblyInfo.cs similarity index 100% rename from src/Hyperledger.Aries/Properties/AssemblyInfo.cs rename to legacy/src/Hyperledger.Aries/Properties/AssemblyInfo.cs diff --git a/src/Hyperledger.Aries/Signatures/DefaultSigningService.cs b/legacy/src/Hyperledger.Aries/Signatures/DefaultSigningService.cs similarity index 100% rename from src/Hyperledger.Aries/Signatures/DefaultSigningService.cs rename to legacy/src/Hyperledger.Aries/Signatures/DefaultSigningService.cs diff --git a/src/Hyperledger.Aries/Signatures/ISigningService.cs b/legacy/src/Hyperledger.Aries/Signatures/ISigningService.cs similarity index 100% rename from src/Hyperledger.Aries/Signatures/ISigningService.cs rename to legacy/src/Hyperledger.Aries/Signatures/ISigningService.cs diff --git a/src/Hyperledger.Aries/Storage/DefaultWalletRecordService.cs b/legacy/src/Hyperledger.Aries/Storage/DefaultWalletRecordService.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/DefaultWalletRecordService.cs rename to legacy/src/Hyperledger.Aries/Storage/DefaultWalletRecordService.cs diff --git a/src/Hyperledger.Aries/Storage/DefaultWalletService.cs b/legacy/src/Hyperledger.Aries/Storage/DefaultWalletService.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/DefaultWalletService.cs rename to legacy/src/Hyperledger.Aries/Storage/DefaultWalletService.cs diff --git a/src/Hyperledger.Aries/Storage/IWalletRecordService.cs b/legacy/src/Hyperledger.Aries/Storage/IWalletRecordService.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/IWalletRecordService.cs rename to legacy/src/Hyperledger.Aries/Storage/IWalletRecordService.cs diff --git a/src/Hyperledger.Aries/Storage/IWalletService.cs b/legacy/src/Hyperledger.Aries/Storage/IWalletService.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/IWalletService.cs rename to legacy/src/Hyperledger.Aries/Storage/IWalletService.cs diff --git a/src/Hyperledger.Aries/Storage/Models/RecordTagAttribute.cs b/legacy/src/Hyperledger.Aries/Storage/Models/RecordTagAttribute.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Models/RecordTagAttribute.cs rename to legacy/src/Hyperledger.Aries/Storage/Models/RecordTagAttribute.cs diff --git a/src/Hyperledger.Aries/Storage/Models/WalletConfiguration.cs b/legacy/src/Hyperledger.Aries/Storage/Models/WalletConfiguration.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Models/WalletConfiguration.cs rename to legacy/src/Hyperledger.Aries/Storage/Models/WalletConfiguration.cs diff --git a/src/Hyperledger.Aries/Storage/Models/WalletCredentials.cs b/legacy/src/Hyperledger.Aries/Storage/Models/WalletCredentials.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Models/WalletCredentials.cs rename to legacy/src/Hyperledger.Aries/Storage/Models/WalletCredentials.cs diff --git a/src/Hyperledger.Aries/Storage/Models/WalletStorageConfiguration.cs b/legacy/src/Hyperledger.Aries/Storage/Models/WalletStorageConfiguration.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Models/WalletStorageConfiguration.cs rename to legacy/src/Hyperledger.Aries/Storage/Models/WalletStorageConfiguration.cs diff --git a/src/Hyperledger.Aries/Storage/Records/RecordBase.cs b/legacy/src/Hyperledger.Aries/Storage/Records/RecordBase.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Records/RecordBase.cs rename to legacy/src/Hyperledger.Aries/Storage/Records/RecordBase.cs diff --git a/src/Hyperledger.Aries/Storage/Records/Search/SearchItem.cs b/legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchItem.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Records/Search/SearchItem.cs rename to legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchItem.cs diff --git a/src/Hyperledger.Aries/Storage/Records/Search/SearchOptions.cs b/legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchOptions.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Records/Search/SearchOptions.cs rename to legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchOptions.cs diff --git a/src/Hyperledger.Aries/Storage/Records/Search/SearchQuery.cs b/legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchQuery.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Records/Search/SearchQuery.cs rename to legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchQuery.cs diff --git a/src/Hyperledger.Aries/Storage/Records/Search/SearchResult.cs b/legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchResult.cs similarity index 100% rename from src/Hyperledger.Aries/Storage/Records/Search/SearchResult.cs rename to legacy/src/Hyperledger.Aries/Storage/Records/Search/SearchResult.cs diff --git a/src/Hyperledger.Aries/Utils/Base64UrlEncoder.cs b/legacy/src/Hyperledger.Aries/Utils/Base64UrlEncoder.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/Base64UrlEncoder.cs rename to legacy/src/Hyperledger.Aries/Utils/Base64UrlEncoder.cs diff --git a/src/Hyperledger.Aries/Utils/CredentialUtils.cs b/legacy/src/Hyperledger.Aries/Utils/CredentialUtils.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/CredentialUtils.cs rename to legacy/src/Hyperledger.Aries/Utils/CredentialUtils.cs diff --git a/src/Hyperledger.Aries/Utils/CryptoUtils.cs b/legacy/src/Hyperledger.Aries/Utils/CryptoUtils.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/CryptoUtils.cs rename to legacy/src/Hyperledger.Aries/Utils/CryptoUtils.cs diff --git a/src/Hyperledger.Aries/Utils/DidUtils.cs b/legacy/src/Hyperledger.Aries/Utils/DidUtils.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/DidUtils.cs rename to legacy/src/Hyperledger.Aries/Utils/DidUtils.cs diff --git a/src/Hyperledger.Aries/Utils/EnvironmentUtils.cs b/legacy/src/Hyperledger.Aries/Utils/EnvironmentUtils.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/EnvironmentUtils.cs rename to legacy/src/Hyperledger.Aries/Utils/EnvironmentUtils.cs diff --git a/src/Hyperledger.Aries/Utils/MessageUtils.cs b/legacy/src/Hyperledger.Aries/Utils/MessageUtils.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/MessageUtils.cs rename to legacy/src/Hyperledger.Aries/Utils/MessageUtils.cs diff --git a/src/Hyperledger.Aries/Utils/ResilienceUtils.cs b/legacy/src/Hyperledger.Aries/Utils/ResilienceUtils.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/ResilienceUtils.cs rename to legacy/src/Hyperledger.Aries/Utils/ResilienceUtils.cs diff --git a/src/Hyperledger.Aries/Utils/TagConstants.cs b/legacy/src/Hyperledger.Aries/Utils/TagConstants.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/TagConstants.cs rename to legacy/src/Hyperledger.Aries/Utils/TagConstants.cs diff --git a/src/Hyperledger.Aries/Utils/UriUtils.cs b/legacy/src/Hyperledger.Aries/Utils/UriUtils.cs similarity index 100% rename from src/Hyperledger.Aries/Utils/UriUtils.cs rename to legacy/src/Hyperledger.Aries/Utils/UriUtils.cs diff --git a/src/Hyperledger.Aries.TestHarness/AgentScenarios.cs b/legacy/test/Hyperledger.Aries.TestHarness/AgentScenarios.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/AgentScenarios.cs rename to legacy/test/Hyperledger.Aries.TestHarness/AgentScenarios.cs diff --git a/src/Hyperledger.Aries.TestHarness/Hyperledger.Aries.TestHarness.csproj b/legacy/test/Hyperledger.Aries.TestHarness/Hyperledger.Aries.TestHarness.csproj similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Hyperledger.Aries.TestHarness.csproj rename to legacy/test/Hyperledger.Aries.TestHarness/Hyperledger.Aries.TestHarness.csproj diff --git a/src/Hyperledger.Aries.TestHarness/Mock/InProcAgent.cs b/legacy/test/Hyperledger.Aries.TestHarness/Mock/InProcAgent.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Mock/InProcAgent.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Mock/InProcAgent.cs diff --git a/src/Hyperledger.Aries.TestHarness/Mock/InProcMessageHandler.cs b/legacy/test/Hyperledger.Aries.TestHarness/Mock/InProcMessageHandler.cs similarity index 97% rename from src/Hyperledger.Aries.TestHarness/Mock/InProcMessageHandler.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Mock/InProcMessageHandler.cs index 5630761a..1d46fe19 100644 --- a/src/Hyperledger.Aries.TestHarness/Mock/InProcMessageHandler.cs +++ b/legacy/test/Hyperledger.Aries.TestHarness/Mock/InProcMessageHandler.cs @@ -1,62 +1,62 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Security.Claims; -using System.Threading; -using System.Threading.Tasks; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Extensions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace Hyperledger.TestHarness.Mock -{ - public class InProcMessageHandler : HttpMessageHandler - { - public InProcAgent TargetAgent { get; set; } - - /// - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - if (TargetAgent is InProcMediatorAgent mediatorAgent && request.Method == HttpMethod.Get) - { - var discoveryConfiguration = await mediatorAgent.HandleDiscoveryAsync(); - - var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); - responseMessage.Content = new StringContent(discoveryConfiguration.ToJson()); - responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); - return responseMessage; - } - else if (request.RequestUri.AbsolutePath.Contains("/tails")) - { - var options = TargetAgent.Provider.GetRequiredService>(); - var file = request.RequestUri.Segments.Last(); - - var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); - responseMessage.Content = new ByteArrayContent(File.ReadAllBytes(Path.Combine(options.Value.RevocationRegistryDirectory, file))); - - return responseMessage; - } - else - { - var response = await TargetAgent.HandleAsync(await request.Content?.ReadAsByteArrayAsync()); - var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); - - if (response != null) - { - responseMessage.Content = new ByteArrayContent(response.Payload); - responseMessage.Content.Headers.ContentType = request.Content?.Headers.ContentType; - } - - return responseMessage; - } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Extensions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Hyperledger.TestHarness.Mock +{ + public class InProcMessageHandler : HttpMessageHandler + { + public InProcAgent TargetAgent { get; set; } + + /// + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (TargetAgent is InProcMediatorAgent mediatorAgent && request.Method == HttpMethod.Get) + { + var discoveryConfiguration = await mediatorAgent.HandleDiscoveryAsync(); + + var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); + responseMessage.Content = new StringContent(discoveryConfiguration.ToJson()); + responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); + return responseMessage; + } + else if (request.RequestUri.AbsolutePath.Contains("/tails")) + { + var options = TargetAgent.Provider.GetRequiredService>(); + var file = request.RequestUri.Segments.Last(); + + var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); + responseMessage.Content = new ByteArrayContent(File.ReadAllBytes(Path.Combine(options.Value.RevocationRegistryDirectory, file))); + + return responseMessage; + } + else + { + var response = await TargetAgent.HandleAsync(await request.Content?.ReadAsByteArrayAsync()); + var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); + + if (response != null) + { + responseMessage.Content = new ByteArrayContent(response.Payload); + responseMessage.Content.Headers.ContentType = request.Content?.Headers.ContentType; + } + + return responseMessage; + } + } + } +} diff --git a/src/Hyperledger.Aries.TestHarness/Mock/MockAgent.cs b/legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgent.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Mock/MockAgent.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgent.cs diff --git a/src/Hyperledger.Aries.TestHarness/Mock/MockAgentHttpHandler.cs b/legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgentHttpHandler.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Mock/MockAgentHttpHandler.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgentHttpHandler.cs diff --git a/src/Hyperledger.Aries.TestHarness/Mock/MockAgentMessageProcessor.cs b/legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgentMessageProcessor.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Mock/MockAgentMessageProcessor.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgentMessageProcessor.cs diff --git a/src/Hyperledger.Aries.TestHarness/Mock/MockAgentRouter.cs b/legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgentRouter.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Mock/MockAgentRouter.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Mock/MockAgentRouter.cs diff --git a/src/Hyperledger.Aries.TestHarness/Mock/MockUtils.cs b/legacy/test/Hyperledger.Aries.TestHarness/Mock/MockUtils.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Mock/MockUtils.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Mock/MockUtils.cs diff --git a/src/Hyperledger.Aries.TestHarness/Scenarios.cs b/legacy/test/Hyperledger.Aries.TestHarness/Scenarios.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Scenarios.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Scenarios.cs diff --git a/src/Hyperledger.Aries.TestHarness/TestConstants.cs b/legacy/test/Hyperledger.Aries.TestHarness/TestConstants.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/TestConstants.cs rename to legacy/test/Hyperledger.Aries.TestHarness/TestConstants.cs diff --git a/src/Hyperledger.Aries.TestHarness/TestSingleWallet.cs b/legacy/test/Hyperledger.Aries.TestHarness/TestSingleWallet.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/TestSingleWallet.cs rename to legacy/test/Hyperledger.Aries.TestHarness/TestSingleWallet.cs diff --git a/src/Hyperledger.Aries.TestHarness/Utils/AgentUtils.cs b/legacy/test/Hyperledger.Aries.TestHarness/Utils/AgentUtils.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Utils/AgentUtils.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Utils/AgentUtils.cs diff --git a/src/Hyperledger.Aries.TestHarness/Utils/PoolUtils.cs b/legacy/test/Hyperledger.Aries.TestHarness/Utils/PoolUtils.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Utils/PoolUtils.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Utils/PoolUtils.cs diff --git a/src/Hyperledger.Aries.TestHarness/Utils/ProofServiceUtils.cs b/legacy/test/Hyperledger.Aries.TestHarness/Utils/ProofServiceUtils.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Utils/ProofServiceUtils.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Utils/ProofServiceUtils.cs diff --git a/src/Hyperledger.Aries.TestHarness/Utils/ServiceUtils.cs b/legacy/test/Hyperledger.Aries.TestHarness/Utils/ServiceUtils.cs similarity index 100% rename from src/Hyperledger.Aries.TestHarness/Utils/ServiceUtils.cs rename to legacy/test/Hyperledger.Aries.TestHarness/Utils/ServiceUtils.cs diff --git a/test/Hyperledger.Aries.Tests/ConfigurationTests.cs b/legacy/test/Hyperledger.Aries.Tests/ConfigurationTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/ConfigurationTests.cs rename to legacy/test/Hyperledger.Aries.Tests/ConfigurationTests.cs diff --git a/test/Hyperledger.Aries.Tests/ConnectionRecordVersioningTests.cs b/legacy/test/Hyperledger.Aries.Tests/ConnectionRecordVersioningTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/ConnectionRecordVersioningTests.cs rename to legacy/test/Hyperledger.Aries.Tests/ConnectionRecordVersioningTests.cs diff --git a/test/Hyperledger.Aries.Tests/ConverterTests.cs b/legacy/test/Hyperledger.Aries.Tests/ConverterTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/ConverterTests.cs rename to legacy/test/Hyperledger.Aries.Tests/ConverterTests.cs diff --git a/test/Hyperledger.Aries.Tests/Decorators/AttachmentContentTests.cs b/legacy/test/Hyperledger.Aries.Tests/Decorators/AttachmentContentTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Decorators/AttachmentContentTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Decorators/AttachmentContentTests.cs diff --git a/test/Hyperledger.Aries.Tests/Decorators/AttachmentDecoratorTests.cs b/legacy/test/Hyperledger.Aries.Tests/Decorators/AttachmentDecoratorTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Decorators/AttachmentDecoratorTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Decorators/AttachmentDecoratorTests.cs diff --git a/test/Hyperledger.Aries.Tests/Decorators/SignatorDecoratorTests.cs b/legacy/test/Hyperledger.Aries.Tests/Decorators/SignatorDecoratorTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Decorators/SignatorDecoratorTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Decorators/SignatorDecoratorTests.cs diff --git a/test/Hyperledger.Aries.Tests/Decorators/ThreadingDecoratorTests.cs b/legacy/test/Hyperledger.Aries.Tests/Decorators/ThreadingDecoratorTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Decorators/ThreadingDecoratorTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Decorators/ThreadingDecoratorTests.cs diff --git a/test/Hyperledger.Aries.Tests/Decorators/TransportDecoratorTests.cs b/legacy/test/Hyperledger.Aries.Tests/Decorators/TransportDecoratorTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Decorators/TransportDecoratorTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Decorators/TransportDecoratorTests.cs diff --git a/test/Hyperledger.Aries.Tests/DidCommServiceTests.cs b/legacy/test/Hyperledger.Aries.Tests/DidCommServiceTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/DidCommServiceTests.cs rename to legacy/test/Hyperledger.Aries.Tests/DidCommServiceTests.cs diff --git a/test/Hyperledger.Aries.Tests/DidDocTests.cs b/legacy/test/Hyperledger.Aries.Tests/DidDocTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/DidDocTests.cs rename to legacy/test/Hyperledger.Aries.Tests/DidDocTests.cs diff --git a/test/Hyperledger.Aries.Tests/DidUtilsTests.cs b/legacy/test/Hyperledger.Aries.Tests/DidUtilsTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/DidUtilsTests.cs rename to legacy/test/Hyperledger.Aries.Tests/DidUtilsTests.cs diff --git a/test/Hyperledger.Aries.Tests/EventAggregatorTests.cs b/legacy/test/Hyperledger.Aries.Tests/EventAggregatorTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/EventAggregatorTests.cs rename to legacy/test/Hyperledger.Aries.Tests/EventAggregatorTests.cs diff --git a/test/Hyperledger.Aries.Tests/Extensions/ObjectExtensions.cs b/legacy/test/Hyperledger.Aries.Tests/Extensions/ObjectExtensions.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Extensions/ObjectExtensions.cs rename to legacy/test/Hyperledger.Aries.Tests/Extensions/ObjectExtensions.cs diff --git a/test/Hyperledger.Aries.Tests/GlobalSuppressions.cs b/legacy/test/Hyperledger.Aries.Tests/GlobalSuppressions.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/GlobalSuppressions.cs rename to legacy/test/Hyperledger.Aries.Tests/GlobalSuppressions.cs diff --git a/test/Hyperledger.Aries.Tests/Hyperledger.Aries.Tests.csproj b/legacy/test/Hyperledger.Aries.Tests/Hyperledger.Aries.Tests.csproj similarity index 100% rename from test/Hyperledger.Aries.Tests/Hyperledger.Aries.Tests.csproj rename to legacy/test/Hyperledger.Aries.Tests/Hyperledger.Aries.Tests.csproj diff --git a/test/Hyperledger.Aries.Tests/InProcAgentTests.cs b/legacy/test/Hyperledger.Aries.Tests/InProcAgentTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/InProcAgentTests.cs rename to legacy/test/Hyperledger.Aries.Tests/InProcAgentTests.cs diff --git a/test/Hyperledger.Aries.Tests/Integration/ConnectionTests.cs b/legacy/test/Hyperledger.Aries.Tests/Integration/ConnectionTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Integration/ConnectionTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Integration/ConnectionTests.cs diff --git a/test/Hyperledger.Aries.Tests/Integration/CredentialTests.cs b/legacy/test/Hyperledger.Aries.Tests/Integration/CredentialTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Integration/CredentialTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Integration/CredentialTests.cs diff --git a/test/Hyperledger.Aries.Tests/Integration/DidExchangeTests.cs b/legacy/test/Hyperledger.Aries.Tests/Integration/DidExchangeTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Integration/DidExchangeTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Integration/DidExchangeTests.cs diff --git a/test/Hyperledger.Aries.Tests/Integration/DiscoveryTests.cs b/legacy/test/Hyperledger.Aries.Tests/Integration/DiscoveryTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Integration/DiscoveryTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Integration/DiscoveryTests.cs diff --git a/test/Hyperledger.Aries.Tests/Integration/MessageTypesTests.cs b/legacy/test/Hyperledger.Aries.Tests/Integration/MessageTypesTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Integration/MessageTypesTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Integration/MessageTypesTests.cs diff --git a/test/Hyperledger.Aries.Tests/Integration/OutOfBandTests.cs b/legacy/test/Hyperledger.Aries.Tests/Integration/OutOfBandTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Integration/OutOfBandTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Integration/OutOfBandTests.cs diff --git a/test/Hyperledger.Aries.Tests/Integration/ProofTests.cs b/legacy/test/Hyperledger.Aries.Tests/Integration/ProofTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Integration/ProofTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Integration/ProofTests.cs diff --git a/test/Hyperledger.Aries.Tests/LedgerServiceTests.cs b/legacy/test/Hyperledger.Aries.Tests/LedgerServiceTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/LedgerServiceTests.cs rename to legacy/test/Hyperledger.Aries.Tests/LedgerServiceTests.cs diff --git a/test/Hyperledger.Aries.Tests/MessageServiceTests.cs b/legacy/test/Hyperledger.Aries.Tests/MessageServiceTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/MessageServiceTests.cs rename to legacy/test/Hyperledger.Aries.Tests/MessageServiceTests.cs diff --git a/test/Hyperledger.Aries.Tests/MessageUtilsTests.cs b/legacy/test/Hyperledger.Aries.Tests/MessageUtilsTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/MessageUtilsTests.cs rename to legacy/test/Hyperledger.Aries.Tests/MessageUtilsTests.cs diff --git a/test/Hyperledger.Aries.Tests/MockExtendedConnectionService.cs b/legacy/test/Hyperledger.Aries.Tests/MockExtendedConnectionService.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/MockExtendedConnectionService.cs rename to legacy/test/Hyperledger.Aries.Tests/MockExtendedConnectionService.cs diff --git a/test/Hyperledger.Aries.Tests/MockMessageHandler.cs b/legacy/test/Hyperledger.Aries.Tests/MockMessageHandler.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/MockMessageHandler.cs rename to legacy/test/Hyperledger.Aries.Tests/MockMessageHandler.cs diff --git a/test/Hyperledger.Aries.Tests/Payments/PaymentTests.cs b/legacy/test/Hyperledger.Aries.Tests/Payments/PaymentTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Payments/PaymentTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Payments/PaymentTests.cs diff --git a/test/Hyperledger.Aries.Tests/Payments/ProtocolTests.cs b/legacy/test/Hyperledger.Aries.Tests/Payments/ProtocolTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Payments/ProtocolTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Payments/ProtocolTests.cs diff --git a/test/Hyperledger.Aries.Tests/Payments/TransferTests.cs b/legacy/test/Hyperledger.Aries.Tests/Payments/TransferTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Payments/TransferTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Payments/TransferTests.cs diff --git a/test/Hyperledger.Aries.Tests/PoolServiceTests.cs b/legacy/test/Hyperledger.Aries.Tests/PoolServiceTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/PoolServiceTests.cs rename to legacy/test/Hyperledger.Aries.Tests/PoolServiceTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/ConnectionTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/ConnectionTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/ConnectionTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/ConnectionTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/CredentialTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialTests.cs similarity index 97% rename from test/Hyperledger.Aries.Tests/Protocols/CredentialTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialTests.cs index 078600bb..9baed2a1 100644 --- a/test/Hyperledger.Aries.Tests/Protocols/CredentialTests.cs +++ b/legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialTests.cs @@ -1,504 +1,504 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Reactive.Linq; -using System.Threading.Tasks; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Contracts; -using Hyperledger.Aries.Extensions; -using Hyperledger.Aries.Features.Handshakes.Connection; -using Hyperledger.Aries.Features.Handshakes.Connection.Models; -using Hyperledger.Aries.Features.IssueCredential; -using Hyperledger.Aries.Ledger; -using Hyperledger.Aries.Models.Events; -using Hyperledger.Aries.Payments; -using Hyperledger.Aries.Runtime; -using Hyperledger.Aries.Storage; -using Hyperledger.Aries.TestHarness; -using Hyperledger.Indy.AnonCredsApi; -using Hyperledger.Indy.DidApi; -using Hyperledger.Indy.PoolApi; -using Hyperledger.Indy.WalletApi; -using Hyperledger.TestHarness; -using Hyperledger.TestHarness.Utils; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Moq; -using Xunit; - -namespace Hyperledger.Aries.Tests.Protocols -{ - public class CredentialTests : IAsyncLifetime - { - static CredentialTests() - { - global::Hyperledger.Aries.Utils.Runtime.SetFlags(Hyperledger.Aries.Utils.Runtime.LedgerLookupRetryFlag); - } - - private readonly string _issuerConfig = $"{{\"id\":\"{Guid.NewGuid()}\"}}"; - private readonly string _holderConfig = $"{{\"id\":\"{Guid.NewGuid()}\"}}"; - private const string Credentials = "{\"key\":\"test_wallet_key\"}"; - - private IAgentContext _issuerWallet; - private IAgentContext _holderWallet; - - private readonly IEventAggregator _eventAggregator; - private readonly IConnectionService _connectionService; - private readonly ICredentialService _credentialService; - private readonly ISchemaService _schemaService; - - private readonly ConcurrentBag _messages = new ConcurrentBag(); - - public CredentialTests() - { - var recordService = new DefaultWalletRecordService(); - var ledgerService = new DefaultLedgerService(new DefaultLedgerSigningService(new DefaultProvisioningService(recordService, new DefaultWalletService(), Options.Create(new AgentOptions())))); - - var messageService = new DefaultMessageService(new Mock>().Object, new IMessageDispatcher[] { }); - - _eventAggregator = new EventAggregator(); - - var provisioning = ServiceUtils.GetDefaultMockProvisioningService(); - var paymentService = new DefaultPaymentService(); - - var clientFactory = new Mock(); - clientFactory.Setup(x => x.CreateClient(It.IsAny())) - .Returns(new HttpClient()); - - var tailsService = new DefaultTailsService(ledgerService, Options.Create(new Configuration.AgentOptions()), clientFactory.Object); - _schemaService = new DefaultSchemaService(provisioning, recordService, ledgerService, paymentService, tailsService, Options.Create(new Configuration.AgentOptions())); - - _connectionService = new DefaultConnectionService( - _eventAggregator, - recordService, - provisioning, - new Mock>().Object); - - _credentialService = new DefaultCredentialService( - _eventAggregator, - ledgerService, - _connectionService, - recordService, - _schemaService, - tailsService, - provisioning, - paymentService, - messageService, - new Mock>().Object); - } - - public async Task InitializeAsync() - { - _issuerWallet = await AgentUtils.Create(_issuerConfig, Credentials, true); - _holderWallet = await AgentUtils.Create(_holderConfig, Credentials, true); - } - - /// - /// This test requires a local running node accessible at 127.0.0.1 - /// - /// The issuance demo. - [Fact] - public async Task CanIssueCredential() - { - var events = 0; - _eventAggregator.GetEventByType() - .Where(_ => (_.MessageType == MessageTypes.IssueCredentialNames.OfferCredential || - _.MessageType == MessageTypes.IssueCredentialNames.RequestCredential || - _.MessageType == MessageTypes.IssueCredentialNames.IssueCredential)) - .Subscribe(_ => - { - events++; - }); - - // Setup secure connection between issuer and holder - var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( - _connectionService, _messages, _issuerWallet, _holderWallet); - - var (issuerCredential, holderCredential) = await Scenarios.IssueCredentialAsync( - _schemaService, _credentialService, _messages, issuerConnection, - holderConnection, _issuerWallet, _holderWallet, await _holderWallet.Pool as Pool, TestConstants.DefaultMasterSecret, false, new List - { - new CredentialPreviewAttribute("first_name", "Test"), - new CredentialPreviewAttribute("last_name", "Holder") - }); - - Assert.True(events == 3); - - Assert.Equal(issuerCredential.State, holderCredential.State); - Assert.Equal(CredentialState.Issued, issuerCredential.State); - } - - [Fact] - public async Task CanStoreAndReceiveMimeTypes() - { - const string pdfFile = "base64_encoded_pdf_file"; - const string pngFile = "base64_encoded_png_image_file"; - const string unknownFile = "base64_encoded_unknown_file"; - - var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( - _connectionService, _messages, _issuerWallet, _holderWallet); - - var (_, holderCredential) = await Scenarios.IssueCredentialAsync( - _schemaService, _credentialService, _messages, issuerConnection, - holderConnection, _issuerWallet, _holderWallet, await _holderWallet.Pool as Pool, TestConstants.DefaultMasterSecret, false, new List - { - new CredentialPreviewAttribute - { - MimeType = CredentialMimeTypes.TextMimeType, - Name = "attribute_name", - Value = "attribute_value" - }, - new CredentialPreviewAttribute - { - MimeType = CredentialMimeTypes.ImagePngMimeType, - Name = pngFile, - Value = pdfFile - }, - new CredentialPreviewAttribute - { - MimeType = CredentialMimeTypes.ApplicationPdfMimeType, - Name = pdfFile, - Value = pdfFile - }, - new CredentialPreviewAttribute - { - Name = unknownFile, - Value = unknownFile - } - }); - - var attributesWithMimeTypeTextCount = 0; - var attributesWithMimeTypeImagePngCount = 0; - var attributesWithMimeTypeApplicationPdfCount = 0; - - foreach (var credentialPreviewAttribute in holderCredential.CredentialAttributesValues) - { - switch (credentialPreviewAttribute.MimeType) - { - case CredentialMimeTypes.TextMimeType: - attributesWithMimeTypeTextCount++; - break; - case CredentialMimeTypes.ImagePngMimeType: - attributesWithMimeTypeImagePngCount++; - break; - case CredentialMimeTypes.ApplicationPdfMimeType: - attributesWithMimeTypeApplicationPdfCount++; - break; - } - } - - Assert.Equal(2, attributesWithMimeTypeTextCount); - Assert.Equal(1, attributesWithMimeTypeImagePngCount); - Assert.Equal(1, attributesWithMimeTypeApplicationPdfCount); - } - - [Fact] - public async Task CanCreateCredentialOffer() - { - var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, - new { seed = TestConstants.StewardSeed }.ToJson()); - - var result = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, - new[] { "test-attr" }); - - var (msg, credentialRecord) = await _credentialService.CreateOfferAsync(_issuerWallet, - new OfferConfiguration { CredentialDefinitionId = result.Item1 }, null); - - Assert.Equal(CredentialState.Offered, credentialRecord.State); - Assert.NotNull(msg); - Assert.Null(msg.CredentialPreview); - } - - [Fact] - public async Task CanCreateCredentialOfferWithPreview() - { - var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, - new { seed = TestConstants.StewardSeed }.ToJson()); - - var result = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, - new[] { "test-attr" }); - - var (msg, credentialRecord) = await _credentialService.CreateOfferAsync(_issuerWallet, - new OfferConfiguration - { - CredentialDefinitionId = result.Item1, - CredentialAttributeValues = new List - { - new CredentialPreviewAttribute("test-attr","test-attr-value") - } - }); - - Assert.Equal(CredentialState.Offered, credentialRecord.State); - Assert.NotNull(msg); - Assert.NotNull(msg.CredentialPreview); - Assert.True(msg.CredentialPreview.Attributes.Count() == 1); - - var previewAttr = msg.CredentialPreview.Attributes.ToArray()[0]; - - Assert.True(previewAttr.Name == "test-attr"); - Assert.True(previewAttr.MimeType == CredentialMimeTypes.TextMimeType); - Assert.True((string)previewAttr.Value == "test-attr-value"); - } - - [Fact] - public async Task RevokeCredentialOfferThrowsCredentialNotFound() - { - var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectOfferAsync(_issuerWallet, "bad-connection-id")); - Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); - } - - [Fact] - public async Task RevokeCredentialOfferThrowsCredentialInvalidState() - { - //Establish a connection between the two parties - var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( - _connectionService, _messages, _issuerWallet, _holderWallet); - - // Create an issuer DID/VK. Can also be created during provisioning - var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, - new { seed = TestConstants.StewardSeed }.ToJson()); - - // Create a schema and credential definition for this issuer - var (definitionId, _) = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, - new[] { "dummy_attr" }); - - var offerConfig = new OfferConfiguration - { - IssuerDid = issuer.Did, - CredentialDefinitionId = definitionId - }; - - // Send an offer to the holder using the established connection channel - var (offer, _) = await _credentialService.CreateOfferAsync(_issuerWallet, offerConfig, issuerConnection.Id); - _messages.Add(offer); - - // Holder retrieves message from their cloud agent - var credentialOffer = FindContentMessage(_messages); - - // Holder processes the credential offer by storing it - var holderCredentialId = - await _credentialService.ProcessOfferAsync(_holderWallet, credentialOffer, holderConnection); - - // Holder creates master secret. Will also be created during wallet agent provisioning - await AnonCreds.ProverCreateMasterSecretAsync(_holderWallet.Wallet, TestConstants.DefaultMasterSecret); - - // Holder accepts the credential offer and sends a credential request - var (request, _) = await _credentialService.CreateRequestAsync(_holderWallet, holderCredentialId); - _messages.Add(request); - - // Issuer retrieves credential request from cloud agent - var credentialRequest = FindContentMessage(_messages); - Assert.NotNull(credentialRequest); - - // Issuer processes the credential request by storing it - var issuerCredentialId = - await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, credentialRequest, issuerConnection); - - var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectOfferAsync(_issuerWallet, issuerCredentialId)); - Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); - } - - [Fact] - public async Task CreateOfferV1AsyncThrowsExceptionConnectionNotFound() - { - var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), "bad-connection-id")); - Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); - } - - [Fact] - public async Task CreateOfferV1AsyncThrowsExceptionConnectionInvalidState() - { - var connectionId = Guid.NewGuid().ToString(); - - await _connectionService.CreateInvitationAsync(_issuerWallet, - new InviteConfiguration { ConnectionId = connectionId, AutoAcceptConnection = false }); - - var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), connectionId)); - Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); - } - - [Fact] - public async Task SendOfferAsyncThrowsExceptionConnectionNotFound() - { - var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), "bad-connection-id")); - Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); - } - - [Fact] - public async Task SendOfferAsyncThrowsExceptionConnectionInvalidState() - { - var connectionId = Guid.NewGuid().ToString(); - - await _connectionService.CreateInvitationAsync(_issuerWallet, - new InviteConfiguration { ConnectionId = connectionId, AutoAcceptConnection = false }); - - var ex = await Assert.ThrowsAsync(async () => - await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), connectionId)); - Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); - } - - [Fact] - public async Task ProcessCredentialRequestThrowsCredentialNotFound() - { - var (issuerConnection, _) = await Scenarios.EstablishConnectionAsync( - _connectionService, _messages, _issuerWallet, _holderWallet); - - var ex = await Assert.ThrowsAsync(async () => await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, - new CredentialRequestMessage(), issuerConnection)); - - Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); - } - - [Fact] - public async Task RejectCredentialRequestThrowsExceptionCredentialNotFound() - { - var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectCredentialRequestAsync(_holderWallet, "bad-credential-id")); - Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); - } - - [Fact] - public async Task RejectCredentialRequestThrowsExceptionCredentialInvalidState() - { - //Establish a connection between the two parties - var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( - _connectionService, _messages, _issuerWallet, _holderWallet); - - // Create an issuer DID/VK. Can also be created during provisioning - var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, - new { seed = TestConstants.StewardSeed }.ToJson()); - - // Create a schema and credential definition for this issuer - var (definitionId, _) = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, - new[] { "dummy_attr" }); - - var offerConfig = new OfferConfiguration - { - IssuerDid = issuer.Did, - CredentialDefinitionId = definitionId - }; - - // Send an offer to the holder using the established connection channel - var (offerMessage, _) = await _credentialService.CreateOfferAsync(_issuerWallet, offerConfig, issuerConnection.Id); - _messages.Add(offerMessage); - - // Holder retrieves message from their cloud agent - var credentialOffer = FindContentMessage(_messages); - - // Holder processes the credential offer by storing it - var holderCredentialId = - await _credentialService.ProcessOfferAsync(_holderWallet, credentialOffer, holderConnection); - - // Holder creates master secret. Will also be created during wallet agent provisioning - await AnonCreds.ProverCreateMasterSecretAsync(_holderWallet.Wallet, TestConstants.DefaultMasterSecret); - - // Holder accepts the credential offer and sends a credential request - (var request, var _) = await _credentialService.CreateRequestAsync(_holderWallet, holderCredentialId); - _messages.Add(request); - - // Issuer retrieves credential request from cloud agent - var credentialRequest = FindContentMessage(_messages); - Assert.NotNull(credentialRequest); - - // Issuer processes the credential request by storing it - var issuerCredentialId = - await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, credentialRequest, issuerConnection); - - await _credentialService.RejectCredentialRequestAsync(_issuerWallet, issuerCredentialId); - - //Try reject the credential request again - var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectCredentialRequestAsync(_issuerWallet, issuerCredentialId)); - Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); - } - - [Fact] - public async Task IssueCredentialThrowsExceptionCredentialNotFound() - { - // Create an issuer DID/VK. Can also be created during provisioning - var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, - new { seed = TestConstants.StewardSeed }.ToJson()); - - var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateCredentialAsync(_issuerWallet, "bad-credential-id")); - Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); - } - - [Fact] - public async Task IssueCredentialThrowsExceptionCredentialInvalidState() - { - //Establish a connection between the two parties - var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( - _connectionService, _messages, _issuerWallet, _holderWallet); - - // Create an issuer DID/VK. Can also be created during provisioning - var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, - new { seed = TestConstants.StewardSeed }.ToJson()); - - // Create a schema and credential definition for this issuer - var (definitionId, _) = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, - new[] { "dummy_attr" }); - - var offerConfig = new OfferConfiguration - { - IssuerDid = issuer.Did, - CredentialDefinitionId = definitionId - }; - - // Send an offer to the holder using the established connection channel - var (message, _) = await _credentialService.CreateOfferAsync(_issuerWallet, offerConfig, issuerConnection.Id); - _messages.Add(message); - - // Holder retrieves message from their cloud agent - var credentialOffer = FindContentMessage(_messages); - - // Holder processes the credential offer by storing it - var holderCredentialId = - await _credentialService.ProcessOfferAsync(_holderWallet, credentialOffer, holderConnection); - - // Holder creates master secret. Will also be created during wallet agent provisioning - await AnonCreds.ProverCreateMasterSecretAsync(_holderWallet.Wallet, TestConstants.DefaultMasterSecret); - - // Holder accepts the credential offer and sends a credential request - var (request, _) = await _credentialService.CreateRequestAsync(_holderWallet, holderCredentialId); - _messages.Add(request); - - // Issuer retrieves credential request from cloud agent - var credentialRequest = FindContentMessage(_messages); - Assert.NotNull(credentialRequest); - - // Issuer processes the credential request by storing it - var issuerCredentialId = - await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, credentialRequest, issuerConnection); - - // Issuer accepts the credential requests and issues a credential - var (credential, _) = await _credentialService.CreateCredentialAsync(_issuerWallet, issuerCredentialId, - new List { new CredentialPreviewAttribute("dummy_attr", "dummyVal") }); - _messages.Add(credential); - - //Try issue the credential again - var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateCredentialAsync(_issuerWallet, issuerCredentialId)); - Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); - } - - [Fact] - public async Task RejectOfferAsyncThrowsExceptionCredentialOfferNotFound() - { - var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectOfferAsync(_issuerWallet, "bad-credential-id")); - Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); - } - - private static T FindContentMessage(IEnumerable collection) - where T : AgentMessage - => collection.OfType().Single(); - - public async Task DisposeAsync() - { - if (_issuerWallet != null) await _issuerWallet.Wallet.CloseAsync(); - if (_holderWallet != null) await _holderWallet.Wallet.CloseAsync(); - - await Wallet.DeleteWalletAsync(_issuerConfig, Credentials); - await Wallet.DeleteWalletAsync(_holderConfig, Credentials); - } - } -} +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Contracts; +using Hyperledger.Aries.Extensions; +using Hyperledger.Aries.Features.Handshakes.Connection; +using Hyperledger.Aries.Features.Handshakes.Connection.Models; +using Hyperledger.Aries.Features.IssueCredential; +using Hyperledger.Aries.Ledger; +using Hyperledger.Aries.Models.Events; +using Hyperledger.Aries.Payments; +using Hyperledger.Aries.Runtime; +using Hyperledger.Aries.Storage; +using Hyperledger.Aries.TestHarness; +using Hyperledger.Indy.AnonCredsApi; +using Hyperledger.Indy.DidApi; +using Hyperledger.Indy.PoolApi; +using Hyperledger.Indy.WalletApi; +using Hyperledger.TestHarness; +using Hyperledger.TestHarness.Utils; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +namespace Hyperledger.Aries.Tests.Protocols +{ + public class CredentialTests : IAsyncLifetime + { + static CredentialTests() + { + global::Hyperledger.Aries.Utils.Runtime.SetFlags(Hyperledger.Aries.Utils.Runtime.LedgerLookupRetryFlag); + } + + private readonly string _issuerConfig = $"{{\"id\":\"{Guid.NewGuid()}\"}}"; + private readonly string _holderConfig = $"{{\"id\":\"{Guid.NewGuid()}\"}}"; + private const string Credentials = "{\"key\":\"test_wallet_key\"}"; + + private IAgentContext _issuerWallet; + private IAgentContext _holderWallet; + + private readonly IEventAggregator _eventAggregator; + private readonly IConnectionService _connectionService; + private readonly ICredentialService _credentialService; + private readonly ISchemaService _schemaService; + + private readonly ConcurrentBag _messages = new ConcurrentBag(); + + public CredentialTests() + { + var recordService = new DefaultWalletRecordService(); + var ledgerService = new DefaultLedgerService(new DefaultLedgerSigningService(new DefaultProvisioningService(recordService, new DefaultWalletService(), Options.Create(new AgentOptions())))); + + var messageService = new DefaultMessageService(new Mock>().Object, new IMessageDispatcher[] { }); + + _eventAggregator = new EventAggregator(); + + var provisioning = ServiceUtils.GetDefaultMockProvisioningService(); + var paymentService = new DefaultPaymentService(); + + var clientFactory = new Mock(); + clientFactory.Setup(x => x.CreateClient(It.IsAny())) + .Returns(new HttpClient()); + + var tailsService = new DefaultTailsService(ledgerService, Options.Create(new Configuration.AgentOptions()), clientFactory.Object); + _schemaService = new DefaultSchemaService(provisioning, recordService, ledgerService, paymentService, tailsService, Options.Create(new Configuration.AgentOptions())); + + _connectionService = new DefaultConnectionService( + _eventAggregator, + recordService, + provisioning, + new Mock>().Object); + + _credentialService = new DefaultCredentialService( + _eventAggregator, + ledgerService, + _connectionService, + recordService, + _schemaService, + tailsService, + provisioning, + paymentService, + messageService, + new Mock>().Object); + } + + public async Task InitializeAsync() + { + _issuerWallet = await AgentUtils.Create(_issuerConfig, Credentials, true); + _holderWallet = await AgentUtils.Create(_holderConfig, Credentials, true); + } + + /// + /// This test requires a local running node accessible at 127.0.0.1 + /// + /// The issuance demo. + [Fact] + public async Task CanIssueCredential() + { + var events = 0; + _eventAggregator.GetEventByType() + .Where(_ => (_.MessageType == MessageTypes.IssueCredentialNames.OfferCredential || + _.MessageType == MessageTypes.IssueCredentialNames.RequestCredential || + _.MessageType == MessageTypes.IssueCredentialNames.IssueCredential)) + .Subscribe(_ => + { + events++; + }); + + // Setup secure connection between issuer and holder + var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( + _connectionService, _messages, _issuerWallet, _holderWallet); + + var (issuerCredential, holderCredential) = await Scenarios.IssueCredentialAsync( + _schemaService, _credentialService, _messages, issuerConnection, + holderConnection, _issuerWallet, _holderWallet, await _holderWallet.Pool as Pool, TestConstants.DefaultMasterSecret, false, new List + { + new CredentialPreviewAttribute("first_name", "Test"), + new CredentialPreviewAttribute("last_name", "Holder") + }); + + Assert.True(events == 3); + + Assert.Equal(issuerCredential.State, holderCredential.State); + Assert.Equal(CredentialState.Issued, issuerCredential.State); + } + + [Fact] + public async Task CanStoreAndReceiveMimeTypes() + { + const string pdfFile = "base64_encoded_pdf_file"; + const string pngFile = "base64_encoded_png_image_file"; + const string unknownFile = "base64_encoded_unknown_file"; + + var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( + _connectionService, _messages, _issuerWallet, _holderWallet); + + var (_, holderCredential) = await Scenarios.IssueCredentialAsync( + _schemaService, _credentialService, _messages, issuerConnection, + holderConnection, _issuerWallet, _holderWallet, await _holderWallet.Pool as Pool, TestConstants.DefaultMasterSecret, false, new List + { + new CredentialPreviewAttribute + { + MimeType = CredentialMimeTypes.TextMimeType, + Name = "attribute_name", + Value = "attribute_value" + }, + new CredentialPreviewAttribute + { + MimeType = CredentialMimeTypes.ImagePngMimeType, + Name = pngFile, + Value = pdfFile + }, + new CredentialPreviewAttribute + { + MimeType = CredentialMimeTypes.ApplicationPdfMimeType, + Name = pdfFile, + Value = pdfFile + }, + new CredentialPreviewAttribute + { + Name = unknownFile, + Value = unknownFile + } + }); + + var attributesWithMimeTypeTextCount = 0; + var attributesWithMimeTypeImagePngCount = 0; + var attributesWithMimeTypeApplicationPdfCount = 0; + + foreach (var credentialPreviewAttribute in holderCredential.CredentialAttributesValues) + { + switch (credentialPreviewAttribute.MimeType) + { + case CredentialMimeTypes.TextMimeType: + attributesWithMimeTypeTextCount++; + break; + case CredentialMimeTypes.ImagePngMimeType: + attributesWithMimeTypeImagePngCount++; + break; + case CredentialMimeTypes.ApplicationPdfMimeType: + attributesWithMimeTypeApplicationPdfCount++; + break; + } + } + + Assert.Equal(2, attributesWithMimeTypeTextCount); + Assert.Equal(1, attributesWithMimeTypeImagePngCount); + Assert.Equal(1, attributesWithMimeTypeApplicationPdfCount); + } + + [Fact] + public async Task CanCreateCredentialOffer() + { + var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, + new { seed = TestConstants.StewardSeed }.ToJson()); + + var result = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, + new[] { "test-attr" }); + + var (msg, credentialRecord) = await _credentialService.CreateOfferAsync(_issuerWallet, + new OfferConfiguration { CredentialDefinitionId = result.Item1 }, null); + + Assert.Equal(CredentialState.Offered, credentialRecord.State); + Assert.NotNull(msg); + Assert.Null(msg.CredentialPreview); + } + + [Fact] + public async Task CanCreateCredentialOfferWithPreview() + { + var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, + new { seed = TestConstants.StewardSeed }.ToJson()); + + var result = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, + new[] { "test-attr" }); + + var (msg, credentialRecord) = await _credentialService.CreateOfferAsync(_issuerWallet, + new OfferConfiguration + { + CredentialDefinitionId = result.Item1, + CredentialAttributeValues = new List + { + new CredentialPreviewAttribute("test-attr","test-attr-value") + } + }); + + Assert.Equal(CredentialState.Offered, credentialRecord.State); + Assert.NotNull(msg); + Assert.NotNull(msg.CredentialPreview); + Assert.True(msg.CredentialPreview.Attributes.Count() == 1); + + var previewAttr = msg.CredentialPreview.Attributes.ToArray()[0]; + + Assert.True(previewAttr.Name == "test-attr"); + Assert.True(previewAttr.MimeType == CredentialMimeTypes.TextMimeType); + Assert.True((string)previewAttr.Value == "test-attr-value"); + } + + [Fact] + public async Task RevokeCredentialOfferThrowsCredentialNotFound() + { + var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectOfferAsync(_issuerWallet, "bad-connection-id")); + Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); + } + + [Fact] + public async Task RevokeCredentialOfferThrowsCredentialInvalidState() + { + //Establish a connection between the two parties + var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( + _connectionService, _messages, _issuerWallet, _holderWallet); + + // Create an issuer DID/VK. Can also be created during provisioning + var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, + new { seed = TestConstants.StewardSeed }.ToJson()); + + // Create a schema and credential definition for this issuer + var (definitionId, _) = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, + new[] { "dummy_attr" }); + + var offerConfig = new OfferConfiguration + { + IssuerDid = issuer.Did, + CredentialDefinitionId = definitionId + }; + + // Send an offer to the holder using the established connection channel + var (offer, _) = await _credentialService.CreateOfferAsync(_issuerWallet, offerConfig, issuerConnection.Id); + _messages.Add(offer); + + // Holder retrieves message from their cloud agent + var credentialOffer = FindContentMessage(_messages); + + // Holder processes the credential offer by storing it + var holderCredentialId = + await _credentialService.ProcessOfferAsync(_holderWallet, credentialOffer, holderConnection); + + // Holder creates master secret. Will also be created during wallet agent provisioning + await AnonCreds.ProverCreateMasterSecretAsync(_holderWallet.Wallet, TestConstants.DefaultMasterSecret); + + // Holder accepts the credential offer and sends a credential request + var (request, _) = await _credentialService.CreateRequestAsync(_holderWallet, holderCredentialId); + _messages.Add(request); + + // Issuer retrieves credential request from cloud agent + var credentialRequest = FindContentMessage(_messages); + Assert.NotNull(credentialRequest); + + // Issuer processes the credential request by storing it + var issuerCredentialId = + await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, credentialRequest, issuerConnection); + + var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectOfferAsync(_issuerWallet, issuerCredentialId)); + Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); + } + + [Fact] + public async Task CreateOfferV1AsyncThrowsExceptionConnectionNotFound() + { + var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), "bad-connection-id")); + Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); + } + + [Fact] + public async Task CreateOfferV1AsyncThrowsExceptionConnectionInvalidState() + { + var connectionId = Guid.NewGuid().ToString(); + + await _connectionService.CreateInvitationAsync(_issuerWallet, + new InviteConfiguration { ConnectionId = connectionId, AutoAcceptConnection = false }); + + var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), connectionId)); + Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); + } + + [Fact] + public async Task SendOfferAsyncThrowsExceptionConnectionNotFound() + { + var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), "bad-connection-id")); + Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); + } + + [Fact] + public async Task SendOfferAsyncThrowsExceptionConnectionInvalidState() + { + var connectionId = Guid.NewGuid().ToString(); + + await _connectionService.CreateInvitationAsync(_issuerWallet, + new InviteConfiguration { ConnectionId = connectionId, AutoAcceptConnection = false }); + + var ex = await Assert.ThrowsAsync(async () => + await _credentialService.CreateOfferAsync(_issuerWallet, new OfferConfiguration(), connectionId)); + Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); + } + + [Fact] + public async Task ProcessCredentialRequestThrowsCredentialNotFound() + { + var (issuerConnection, _) = await Scenarios.EstablishConnectionAsync( + _connectionService, _messages, _issuerWallet, _holderWallet); + + var ex = await Assert.ThrowsAsync(async () => await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, + new CredentialRequestMessage(), issuerConnection)); + + Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); + } + + [Fact] + public async Task RejectCredentialRequestThrowsExceptionCredentialNotFound() + { + var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectCredentialRequestAsync(_holderWallet, "bad-credential-id")); + Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); + } + + [Fact] + public async Task RejectCredentialRequestThrowsExceptionCredentialInvalidState() + { + //Establish a connection between the two parties + var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( + _connectionService, _messages, _issuerWallet, _holderWallet); + + // Create an issuer DID/VK. Can also be created during provisioning + var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, + new { seed = TestConstants.StewardSeed }.ToJson()); + + // Create a schema and credential definition for this issuer + var (definitionId, _) = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, + new[] { "dummy_attr" }); + + var offerConfig = new OfferConfiguration + { + IssuerDid = issuer.Did, + CredentialDefinitionId = definitionId + }; + + // Send an offer to the holder using the established connection channel + var (offerMessage, _) = await _credentialService.CreateOfferAsync(_issuerWallet, offerConfig, issuerConnection.Id); + _messages.Add(offerMessage); + + // Holder retrieves message from their cloud agent + var credentialOffer = FindContentMessage(_messages); + + // Holder processes the credential offer by storing it + var holderCredentialId = + await _credentialService.ProcessOfferAsync(_holderWallet, credentialOffer, holderConnection); + + // Holder creates master secret. Will also be created during wallet agent provisioning + await AnonCreds.ProverCreateMasterSecretAsync(_holderWallet.Wallet, TestConstants.DefaultMasterSecret); + + // Holder accepts the credential offer and sends a credential request + (var request, var _) = await _credentialService.CreateRequestAsync(_holderWallet, holderCredentialId); + _messages.Add(request); + + // Issuer retrieves credential request from cloud agent + var credentialRequest = FindContentMessage(_messages); + Assert.NotNull(credentialRequest); + + // Issuer processes the credential request by storing it + var issuerCredentialId = + await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, credentialRequest, issuerConnection); + + await _credentialService.RejectCredentialRequestAsync(_issuerWallet, issuerCredentialId); + + //Try reject the credential request again + var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectCredentialRequestAsync(_issuerWallet, issuerCredentialId)); + Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); + } + + [Fact] + public async Task IssueCredentialThrowsExceptionCredentialNotFound() + { + // Create an issuer DID/VK. Can also be created during provisioning + var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, + new { seed = TestConstants.StewardSeed }.ToJson()); + + var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateCredentialAsync(_issuerWallet, "bad-credential-id")); + Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); + } + + [Fact] + public async Task IssueCredentialThrowsExceptionCredentialInvalidState() + { + //Establish a connection between the two parties + var (issuerConnection, holderConnection) = await Scenarios.EstablishConnectionAsync( + _connectionService, _messages, _issuerWallet, _holderWallet); + + // Create an issuer DID/VK. Can also be created during provisioning + var issuer = await Did.CreateAndStoreMyDidAsync(_issuerWallet.Wallet, + new { seed = TestConstants.StewardSeed }.ToJson()); + + // Create a schema and credential definition for this issuer + var (definitionId, _) = await Scenarios.CreateDummySchemaAndNonRevokableCredDef(_issuerWallet, _schemaService, issuer.Did, + new[] { "dummy_attr" }); + + var offerConfig = new OfferConfiguration + { + IssuerDid = issuer.Did, + CredentialDefinitionId = definitionId + }; + + // Send an offer to the holder using the established connection channel + var (message, _) = await _credentialService.CreateOfferAsync(_issuerWallet, offerConfig, issuerConnection.Id); + _messages.Add(message); + + // Holder retrieves message from their cloud agent + var credentialOffer = FindContentMessage(_messages); + + // Holder processes the credential offer by storing it + var holderCredentialId = + await _credentialService.ProcessOfferAsync(_holderWallet, credentialOffer, holderConnection); + + // Holder creates master secret. Will also be created during wallet agent provisioning + await AnonCreds.ProverCreateMasterSecretAsync(_holderWallet.Wallet, TestConstants.DefaultMasterSecret); + + // Holder accepts the credential offer and sends a credential request + var (request, _) = await _credentialService.CreateRequestAsync(_holderWallet, holderCredentialId); + _messages.Add(request); + + // Issuer retrieves credential request from cloud agent + var credentialRequest = FindContentMessage(_messages); + Assert.NotNull(credentialRequest); + + // Issuer processes the credential request by storing it + var issuerCredentialId = + await _credentialService.ProcessCredentialRequestAsync(_issuerWallet, credentialRequest, issuerConnection); + + // Issuer accepts the credential requests and issues a credential + var (credential, _) = await _credentialService.CreateCredentialAsync(_issuerWallet, issuerCredentialId, + new List { new CredentialPreviewAttribute("dummy_attr", "dummyVal") }); + _messages.Add(credential); + + //Try issue the credential again + var ex = await Assert.ThrowsAsync(async () => await _credentialService.CreateCredentialAsync(_issuerWallet, issuerCredentialId)); + Assert.True(ex.ErrorCode == ErrorCode.RecordInInvalidState); + } + + [Fact] + public async Task RejectOfferAsyncThrowsExceptionCredentialOfferNotFound() + { + var ex = await Assert.ThrowsAsync(async () => await _credentialService.RejectOfferAsync(_issuerWallet, "bad-credential-id")); + Assert.True(ex.ErrorCode == ErrorCode.RecordNotFound); + } + + private static T FindContentMessage(IEnumerable collection) + where T : AgentMessage + => collection.OfType().Single(); + + public async Task DisposeAsync() + { + if (_issuerWallet != null) await _issuerWallet.Wallet.CloseAsync(); + if (_holderWallet != null) await _holderWallet.Wallet.CloseAsync(); + + await Wallet.DeleteWalletAsync(_issuerConfig, Credentials); + await Wallet.DeleteWalletAsync(_holderConfig, Credentials); + } + } +} diff --git a/test/Hyperledger.Aries.Tests/Protocols/CredentialTransientTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialTransientTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/CredentialTransientTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialTransientTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/CredentialUtilsTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialUtilsTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/CredentialUtilsTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialUtilsTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/CredentialV1Tests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialV1Tests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/CredentialV1Tests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/CredentialV1Tests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/DidExchangeTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/DidExchangeTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/DidExchangeTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/DidExchangeTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/DiscoveryTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/DiscoveryTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/DiscoveryTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/DiscoveryTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/OutOfBandTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/OutOfBandTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/OutOfBandTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/OutOfBandTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/ProofTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/ProofTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/ProofTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/ProofTests.cs diff --git a/test/Hyperledger.Aries.Tests/Protocols/RevocationTests.cs b/legacy/test/Hyperledger.Aries.Tests/Protocols/RevocationTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Protocols/RevocationTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Protocols/RevocationTests.cs diff --git a/test/Hyperledger.Aries.Tests/ProvisioningServiceTests.cs b/legacy/test/Hyperledger.Aries.Tests/ProvisioningServiceTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/ProvisioningServiceTests.cs rename to legacy/test/Hyperledger.Aries.Tests/ProvisioningServiceTests.cs diff --git a/test/Hyperledger.Aries.Tests/RecordTests.cs b/legacy/test/Hyperledger.Aries.Tests/RecordTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/RecordTests.cs rename to legacy/test/Hyperledger.Aries.Tests/RecordTests.cs diff --git a/test/Hyperledger.Aries.Tests/Routing/BackupTests.cs b/legacy/test/Hyperledger.Aries.Tests/Routing/BackupTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Routing/BackupTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Routing/BackupTests.cs diff --git a/test/Hyperledger.Aries.Tests/Routing/RoutingInboxHandlerTests.cs b/legacy/test/Hyperledger.Aries.Tests/Routing/RoutingInboxHandlerTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Routing/RoutingInboxHandlerTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Routing/RoutingInboxHandlerTests.cs diff --git a/test/Hyperledger.Aries.Tests/Routing/RoutingTests.cs b/legacy/test/Hyperledger.Aries.Tests/Routing/RoutingTests.cs similarity index 98% rename from test/Hyperledger.Aries.Tests/Routing/RoutingTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Routing/RoutingTests.cs index 7ecd9479..79f85dec 100644 --- a/test/Hyperledger.Aries.Tests/Routing/RoutingTests.cs +++ b/legacy/test/Hyperledger.Aries.Tests/Routing/RoutingTests.cs @@ -1,96 +1,96 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using FluentAssertions; -using Hyperledger.Aries.Agents.Edge; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Features.Handshakes.Common; -using Hyperledger.Aries.Routing; -using Hyperledger.Aries.Storage; -using Hyperledger.TestHarness.Mock; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Hyperledger.Aries.Tests.Routing -{ - - /// - /// Routing Tests - /// - public class RoutingTests - { - [Fact(DisplayName = "Provision and connect a mediator and edge agent")] - public async Task CreatePairedAgentsWithRouting() - { - var pair = await InProcAgent.CreatePairedWithRoutingAsync(); - - var connections1 = await pair.Agent1.Connections.ListAsync(pair.Agent1.Context); - var invitation1 = connections1.FirstOrDefault(x => x.State == ConnectionState.Invited); - - var connection1 = connections1.FirstOrDefault(x => x.Id != invitation1.Id); - var connection2 = (await pair.Agent2.Connections.ListAsync(pair.Agent2.Context)).FirstOrDefault(); - - var provisioning1 = await pair.Agent1.Host.Services.GetRequiredService() - .GetProvisioningAsync(pair.Agent1.Context.Wallet); - var provisioning2 = await pair.Agent2.Host.Services.GetRequiredService() - .GetProvisioningAsync(pair.Agent2.Context.Wallet); - - // Connections exist - Assert.NotNull(invitation1); - Assert.NotNull(connection1); - Assert.NotNull(connection2); - - // The two connections are connected in the correct state - Assert.Equal(ConnectionState.Connected, connection1.State); - Assert.Equal(ConnectionState.Connected, connection2.State); - - // Check mediator and edge provisioning record states - Assert.Equal(provisioning1.GetTag(MediatorProvisioningService.EdgeInvitationTagName), invitation1.Id); - Assert.Equal(provisioning2.GetTag(EdgeProvisioningService.MediatorConnectionIdTagName), connection2.Id); - - string inboxId = connection1.GetTag("InboxId"); - IWalletRecordService recordService = pair.Agent1.Host.Services.GetRequiredService(); - InboxRecord inboxRecord = await recordService.GetAsync(pair.Agent1.Context.Wallet, inboxId); - inboxRecord.GetTag("tag").Should().BeNull(); - } - - [Fact(DisplayName = "Provision and connect a mediator and edge agent with metadata provided")] - public async Task CreatePairedAgentsWithRoutingAndMetadata() - { - Dictionary metaData = new Dictionary() - { - { "tag", "value" } - }; - var pair = await InProcAgent.CreatePairedWithRoutingAsync(metaData); - - var connections1 = await pair.Agent1.Connections.ListAsync(pair.Agent1.Context); - var invitation1 = connections1.FirstOrDefault(x => x.State == ConnectionState.Invited); - - var connection1 = connections1.FirstOrDefault(x => x.Id != invitation1.Id); - var connection2 = (await pair.Agent2.Connections.ListAsync(pair.Agent2.Context)).FirstOrDefault(); - - var provisioning1 = await pair.Agent1.Host.Services.GetRequiredService() - .GetProvisioningAsync(pair.Agent1.Context.Wallet); - var provisioning2 = await pair.Agent2.Host.Services.GetRequiredService() - .GetProvisioningAsync(pair.Agent2.Context.Wallet); - - // Connections exist - invitation1.Should().NotBeNull(); - connection1.Should().NotBeNull(); - connection2.Should().NotBeNull(); - - // The two connections are connected in the correct state - ConnectionState.Connected.Should().Be(connection1.State); - ConnectionState.Connected.Should().Be(connection2.State); - - // Check mediator and edge provisioning record states - provisioning1.GetTag(MediatorProvisioningService.EdgeInvitationTagName).Should().Be(invitation1.Id); - provisioning2.GetTag(EdgeProvisioningService.MediatorConnectionIdTagName).Should().Be(connection2.Id); - - string inboxId = connection1.GetTag("InboxId"); - IWalletRecordService recordService = pair.Agent1.Host.Services.GetRequiredService(); - InboxRecord inboxRecord = await recordService.GetAsync(pair.Agent1.Context.Wallet, inboxId); - inboxRecord.GetTag("tag").Should().Be(metaData["tag"]); - } - } -} +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using Hyperledger.Aries.Agents.Edge; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Features.Handshakes.Common; +using Hyperledger.Aries.Routing; +using Hyperledger.Aries.Storage; +using Hyperledger.TestHarness.Mock; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Hyperledger.Aries.Tests.Routing +{ + + /// + /// Routing Tests + /// + public class RoutingTests + { + [Fact(DisplayName = "Provision and connect a mediator and edge agent")] + public async Task CreatePairedAgentsWithRouting() + { + var pair = await InProcAgent.CreatePairedWithRoutingAsync(); + + var connections1 = await pair.Agent1.Connections.ListAsync(pair.Agent1.Context); + var invitation1 = connections1.FirstOrDefault(x => x.State == ConnectionState.Invited); + + var connection1 = connections1.FirstOrDefault(x => x.Id != invitation1.Id); + var connection2 = (await pair.Agent2.Connections.ListAsync(pair.Agent2.Context)).FirstOrDefault(); + + var provisioning1 = await pair.Agent1.Host.Services.GetRequiredService() + .GetProvisioningAsync(pair.Agent1.Context.Wallet); + var provisioning2 = await pair.Agent2.Host.Services.GetRequiredService() + .GetProvisioningAsync(pair.Agent2.Context.Wallet); + + // Connections exist + Assert.NotNull(invitation1); + Assert.NotNull(connection1); + Assert.NotNull(connection2); + + // The two connections are connected in the correct state + Assert.Equal(ConnectionState.Connected, connection1.State); + Assert.Equal(ConnectionState.Connected, connection2.State); + + // Check mediator and edge provisioning record states + Assert.Equal(provisioning1.GetTag(MediatorProvisioningService.EdgeInvitationTagName), invitation1.Id); + Assert.Equal(provisioning2.GetTag(EdgeProvisioningService.MediatorConnectionIdTagName), connection2.Id); + + string inboxId = connection1.GetTag("InboxId"); + IWalletRecordService recordService = pair.Agent1.Host.Services.GetRequiredService(); + InboxRecord inboxRecord = await recordService.GetAsync(pair.Agent1.Context.Wallet, inboxId); + inboxRecord.GetTag("tag").Should().BeNull(); + } + + [Fact(DisplayName = "Provision and connect a mediator and edge agent with metadata provided")] + public async Task CreatePairedAgentsWithRoutingAndMetadata() + { + Dictionary metaData = new Dictionary() + { + { "tag", "value" } + }; + var pair = await InProcAgent.CreatePairedWithRoutingAsync(metaData); + + var connections1 = await pair.Agent1.Connections.ListAsync(pair.Agent1.Context); + var invitation1 = connections1.FirstOrDefault(x => x.State == ConnectionState.Invited); + + var connection1 = connections1.FirstOrDefault(x => x.Id != invitation1.Id); + var connection2 = (await pair.Agent2.Connections.ListAsync(pair.Agent2.Context)).FirstOrDefault(); + + var provisioning1 = await pair.Agent1.Host.Services.GetRequiredService() + .GetProvisioningAsync(pair.Agent1.Context.Wallet); + var provisioning2 = await pair.Agent2.Host.Services.GetRequiredService() + .GetProvisioningAsync(pair.Agent2.Context.Wallet); + + // Connections exist + invitation1.Should().NotBeNull(); + connection1.Should().NotBeNull(); + connection2.Should().NotBeNull(); + + // The two connections are connected in the correct state + ConnectionState.Connected.Should().Be(connection1.State); + ConnectionState.Connected.Should().Be(connection2.State); + + // Check mediator and edge provisioning record states + provisioning1.GetTag(MediatorProvisioningService.EdgeInvitationTagName).Should().Be(invitation1.Id); + provisioning2.GetTag(EdgeProvisioningService.MediatorConnectionIdTagName).Should().Be(connection2.Id); + + string inboxId = connection1.GetTag("InboxId"); + IWalletRecordService recordService = pair.Agent1.Host.Services.GetRequiredService(); + InboxRecord inboxRecord = await recordService.GetAsync(pair.Agent1.Context.Wallet, inboxId); + inboxRecord.GetTag("tag").Should().Be(metaData["tag"]); + } + } +} diff --git a/test/Hyperledger.Aries.Tests/Routing/WalletBackupTests.cs b/legacy/test/Hyperledger.Aries.Tests/Routing/WalletBackupTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Routing/WalletBackupTests.cs rename to legacy/test/Hyperledger.Aries.Tests/Routing/WalletBackupTests.cs diff --git a/test/Hyperledger.Aries.Tests/RuntimeTests.cs b/legacy/test/Hyperledger.Aries.Tests/RuntimeTests.cs similarity index 97% rename from test/Hyperledger.Aries.Tests/RuntimeTests.cs rename to legacy/test/Hyperledger.Aries.Tests/RuntimeTests.cs index 6d6ac24d..6c2fa848 100644 --- a/test/Hyperledger.Aries.Tests/RuntimeTests.cs +++ b/legacy/test/Hyperledger.Aries.Tests/RuntimeTests.cs @@ -1,42 +1,42 @@ -using Autofac; -using Autofac.Extensions.DependencyInjection; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Configuration; -using Hyperledger.Aries.Contracts; -using Hyperledger.Aries.Features.Handshakes.Connection; -using Hyperledger.Aries.Features.IssueCredential; -using Hyperledger.Aries.Features.PresentProof; -using Hyperledger.Aries.Storage; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Hyperledger.Aries.Tests -{ - public class RuntimeTests - { - [Fact] - public void ResolveDependencyServices() - { - var services = new ServiceCollection(); - services.AddAriesFramework(); - - // Initialize Autofac - var builder = new ContainerBuilder(); - builder.Populate(services); - - // Build the final container - var container = builder.Build(); - - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - Assert.NotNull(container.Resolve()); - } - } -} +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Hyperledger.Aries.Agents; +using Hyperledger.Aries.Configuration; +using Hyperledger.Aries.Contracts; +using Hyperledger.Aries.Features.Handshakes.Connection; +using Hyperledger.Aries.Features.IssueCredential; +using Hyperledger.Aries.Features.PresentProof; +using Hyperledger.Aries.Storage; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Hyperledger.Aries.Tests +{ + public class RuntimeTests + { + [Fact] + public void ResolveDependencyServices() + { + var services = new ServiceCollection(); + services.AddAriesFramework(); + + // Initialize Autofac + var builder = new ContainerBuilder(); + builder.Populate(services); + + // Build the final container + var container = builder.Build(); + + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + Assert.NotNull(container.Resolve()); + } + } +} diff --git a/test/Hyperledger.Aries.Tests/SchemaServiceTests.cs b/legacy/test/Hyperledger.Aries.Tests/SchemaServiceTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/SchemaServiceTests.cs rename to legacy/test/Hyperledger.Aries.Tests/SchemaServiceTests.cs diff --git a/test/Hyperledger.Aries.Tests/SearchTests.cs b/legacy/test/Hyperledger.Aries.Tests/SearchTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/SearchTests.cs rename to legacy/test/Hyperledger.Aries.Tests/SearchTests.cs diff --git a/test/Hyperledger.Aries.Tests/StateMachineTests.cs b/legacy/test/Hyperledger.Aries.Tests/StateMachineTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/StateMachineTests.cs rename to legacy/test/Hyperledger.Aries.Tests/StateMachineTests.cs diff --git a/test/Hyperledger.Aries.Tests/Storage/Models/WalletStorageConfigurationTest.cs b/legacy/test/Hyperledger.Aries.Tests/Storage/Models/WalletStorageConfigurationTest.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/Storage/Models/WalletStorageConfigurationTest.cs rename to legacy/test/Hyperledger.Aries.Tests/Storage/Models/WalletStorageConfigurationTest.cs diff --git a/test/Hyperledger.Aries.Tests/WalletTests.cs b/legacy/test/Hyperledger.Aries.Tests/WalletTests.cs similarity index 100% rename from test/Hyperledger.Aries.Tests/WalletTests.cs rename to legacy/test/Hyperledger.Aries.Tests/WalletTests.cs diff --git a/test/Hyperledger.Aries.Tests/pool_genesis.txn b/legacy/test/Hyperledger.Aries.Tests/pool_genesis.txn similarity index 100% rename from test/Hyperledger.Aries.Tests/pool_genesis.txn rename to legacy/test/Hyperledger.Aries.Tests/pool_genesis.txn diff --git a/scripts/start-node-pool.sh b/scripts/start-node-pool.sh deleted file mode 100644 index bba73596..00000000 --- a/scripts/start-node-pool.sh +++ /dev/null @@ -1,3 +0,0 @@ -docker container rm indy_pool -docker build -f ../docker/indy-pool.dockerfile -t indy_pool . -docker run --name indy_pool -itd -p 9701-9709:9701-9709 indy_pool \ No newline at end of file diff --git a/scripts/start-web-agents.sh b/scripts/start-web-agents.sh deleted file mode 100644 index 6d7635ee..00000000 --- a/scripts/start-web-agents.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -echo 'Starting NGROK' -ngrok start -config web-agents-ngrok-config.yaml --all > /dev/null & -sleep 2s -ngrok_hosts=$(curl --silent --show-error http://localhost:5037/api/tunnels | sed -nE 's/.*public_url":"http:..([^"]*).*public_url":"http:..([^"]*).*/\1|\2/p') -IFS="|" read -r host2 host1 <<< "$ngrok_hosts" - -export HOST1="http://$host1" -export HOST2="http://$host2" - -echo "NGROK started" - -echo "Starting Web Agents with public urls $HOST1 $HOST2" -docker-compose -f ../docker-compose.yaml build -docker-compose -f ../docker-compose.yaml up \ No newline at end of file diff --git a/scripts/stop-node-pool.sh b/scripts/stop-node-pool.sh deleted file mode 100644 index b0ea27cf..00000000 --- a/scripts/stop-node-pool.sh +++ /dev/null @@ -1 +0,0 @@ -docker stop indy_pool \ No newline at end of file diff --git a/scripts/tester.sh b/scripts/tester.sh deleted file mode 100755 index 86015d6c..00000000 --- a/scripts/tester.sh +++ /dev/null @@ -1,8 +0,0 @@ -#! /bin/sh - -# Will run any tests that have the Keyword in their name. -# Example: DisplayName~Aries will run all Tests -# Example: DisplayName~ProofTests will only run ProofTests - -(cd test/Hyperledger.Aries.Tests && \ -dotnet test --nologo --filter DisplayName~Aries --verbosity normal) \ No newline at end of file diff --git a/scripts/web-agents-ngrok-config.yaml b/scripts/web-agents-ngrok-config.yaml deleted file mode 100644 index 2bf1d464..00000000 --- a/scripts/web-agents-ngrok-config.yaml +++ /dev/null @@ -1,12 +0,0 @@ -web_addr: 5037 -tunnels: - web-agent-1: - addr: 7000 - proto: http - host_header: "localhost:7000" - bind-tls: false - web-agent-2: - addr: 8000 - proto: http - host_header: "localhost:8000" - bind-tls: false \ No newline at end of file diff --git a/src/WalletFramework.Core/ClaimPaths/ClaimPath.cs b/src/WalletFramework.Core/ClaimPaths/ClaimPath.cs index 9f73e679..874a0184 100644 --- a/src/WalletFramework.Core/ClaimPaths/ClaimPath.cs +++ b/src/WalletFramework.Core/ClaimPaths/ClaimPath.cs @@ -1,3 +1,5 @@ +using System.Text; +using LanguageExt; using WalletFramework.Core.ClaimPaths.Errors; using WalletFramework.Core.Functional; using WalletFramework.Core.Path; @@ -31,18 +33,61 @@ from components in array.TraverseAll(ClaimPathComponent.Create) from path in FromComponents(components) select path; } + + public static JArray ToJArray(ClaimPath claimPath) + { + var array = new JArray(); + foreach (var component in claimPath.GetPathComponents()) + { + component.Match( + key => + { + array.Add(new JValue(key)); + return Unit.Default; + }, + index => + { + array.Add(new JValue(index)); + return Unit.Default; + }, + _ => + { + array.Add(JValue.CreateNull()); + return Unit.Default; + } + ); + } + return array; + } } public static class ClaimPathFun { public static JsonPath ToJsonPath(this ClaimPath claimPath) { - var jsonPath = "$." + string.Join('.', claimPath.GetPathComponents().Select(x => + var jsonPath = new StringBuilder(); + jsonPath.Append('$'); + + foreach (var component in claimPath.GetPathComponents()) { - if (x.IsKey) return x.AsKey(); - if (x.IsIndex) return x.AsIndex()?.ToString(); - return null; - }).Where(x => x is not null)); - return JsonPath.ValidJsonPath(jsonPath).UnwrapOrThrow(); + component.Match( + key => + { + jsonPath.Append($".{key}"); + return Unit.Default; + }, + integer => + { + jsonPath.Append($"[{integer}]"); + return Unit.Default; + }, + _ => + { + jsonPath.Append("[*]"); + return Unit.Default; + }); + } + + return JsonPath.ValidJsonPath(jsonPath.ToString()).UnwrapOrThrow(); } } diff --git a/src/WalletFramework.Core/Credentials/CredentialId.cs b/src/WalletFramework.Core/Credentials/CredentialId.cs index 732ed46b..043695fa 100644 --- a/src/WalletFramework.Core/Credentials/CredentialId.cs +++ b/src/WalletFramework.Core/Credentials/CredentialId.cs @@ -3,7 +3,7 @@ namespace WalletFramework.Core.Credentials; -public readonly struct CredentialId +public readonly record struct CredentialId { private string Value { get; } @@ -12,6 +12,8 @@ private CredentialId(string value) Value = value; } + public string AsString() => Value; + public override string ToString() => Value; public static implicit operator string(CredentialId credentialId) => credentialId.Value; diff --git a/src/WalletFramework.Core/Credentials/CredentialSetId.cs b/src/WalletFramework.Core/Credentials/CredentialSetId.cs index 8561dd54..b6efc8de 100644 --- a/src/WalletFramework.Core/Credentials/CredentialSetId.cs +++ b/src/WalletFramework.Core/Credentials/CredentialSetId.cs @@ -12,6 +12,10 @@ private CredentialSetId(string value) Value = value; } + public string AsString() => Value; + + public Guid AsGuid() => Guid.Parse(Value); + public override string ToString() => Value; public static implicit operator string(CredentialSetId credentialSetId) => credentialSetId.Value; diff --git a/src/WalletFramework.Core/Cryptography/Models/KeyId.cs b/src/WalletFramework.Core/Cryptography/Models/KeyId.cs index 8b56acb2..bc3af472 100644 --- a/src/WalletFramework.Core/Cryptography/Models/KeyId.cs +++ b/src/WalletFramework.Core/Cryptography/Models/KeyId.cs @@ -9,6 +9,8 @@ public readonly struct KeyId private KeyId(string value) => Value = value; + public string AsString() => Value; + public override string ToString() => Value; public static implicit operator string(KeyId keyId) => keyId.Value; diff --git a/src/WalletFramework.Core/Events/EventAggregator.cs b/src/WalletFramework.Core/Events/EventAggregator.cs new file mode 100644 index 00000000..f49bbf05 --- /dev/null +++ b/src/WalletFramework.Core/Events/EventAggregator.cs @@ -0,0 +1,17 @@ +using System.Reactive.Linq; +using System.Reactive.Subjects; + +namespace WalletFramework.Core.Events; + +/// +//Modified from https://github.com/shiftkey/Reactive.EventAggregator +public class EventAggregator : IEventAggregator +{ + private readonly Subject _subject = new(); + + /// + public IObservable GetEventByType() => _subject.OfType().AsObservable(); + + /// + public void Publish(TEvent eventToPublish) => _subject.OnNext(eventToPublish!); +} diff --git a/src/WalletFramework.Core/Events/IEventAggregator.cs b/src/WalletFramework.Core/Events/IEventAggregator.cs new file mode 100644 index 00000000..391f9628 --- /dev/null +++ b/src/WalletFramework.Core/Events/IEventAggregator.cs @@ -0,0 +1,25 @@ +namespace WalletFramework.Core.Events; + +/// +/// Event Aggregator pattern implementation for decoupled event handling. +/// Allows components to communicate through events without direct dependencies. +/// +/// +/// Modified from https://github.com/shiftkey/Reactive.EventAggregator +/// +public interface IEventAggregator +{ + /// + /// Gets an observable stream for a specific event type. + /// + /// The type of event to observe + /// An IObservable that emits events of type TEvent when they are published + IObservable GetEventByType(); + + /// + /// Publishes an event to all subscribers. + /// + /// The type of event being published + /// The event instance to publish to subscribers + void Publish(TEvent eventToPublish); +} diff --git a/src/WalletFramework.Core/Functional/Validation.cs b/src/WalletFramework.Core/Functional/Validation.cs index cdffef9d..e142e024 100644 --- a/src/WalletFramework.Core/Functional/Validation.cs +++ b/src/WalletFramework.Core/Functional/Validation.cs @@ -291,21 +291,105 @@ from outer in stackedValidation from inner in outer select inner; + /// + /// Unsafely unwraps the value from a or throws the provided . + /// + /// The validation to unwrap. + /// The exception to throw when the validation is invalid. + /// The successful value type. + /// + /// This is an unpure escape hatch intended for boundaries where exceptions are preferred. + /// If you need a richer error message, prefer the overload without the exception parameter which aggregates validation errors. + /// public static T UnwrapOrThrow(this Validation validation, Exception e) => validation.Match( t => t, _ => throw e); + /// + /// Unsafely unwraps the value from a or throws an + /// that includes aggregated validation error messages and inner exceptions (if present). + /// + /// The validation to unwrap. + /// The successful value type. + /// + /// Thrown when the validation is invalid. The exception message contains a summary of all validation errors and the + /// inner exception is an if any underlying exceptions were provided by the errors. + /// + /// + /// This is an unpure escape hatch intended for boundaries where exceptions are preferred. For external input + /// purification, continue using . + /// public static T UnwrapOrThrow(this Validation validation) => - validation.UnwrapOrThrow(new InvalidOperationException($"Value of Type `{typeof(T)}` is corrupt")); + validation.Match( + t => t, + errors => throw CreateInvalidOperationWithErrors(errors)); + /// + /// Unsafely unwraps the value from a or throws the provided . + /// + /// The validation to unwrap. + /// The exception to throw when the validation is invalid. + /// The successful value type. + /// The error type carried by the validation. + /// + /// This is an unpure escape hatch intended for boundaries where exceptions are preferred. + /// If you need a richer error message, prefer the overload without the exception parameter which aggregates validation errors. + /// public static T UnwrapOrThrow(this Validation validation, Exception e) => validation.Match( t => t, _ => throw e); - public static T UnwrapOrThrow(this Validation validation) => - validation.UnwrapOrThrow(new InvalidOperationException($"Value of Type `{typeof(T)}` is corrupt")); + /// + /// Unsafely unwraps the value from a or throws an + /// that includes aggregated validation error messages and inner exceptions (if present). + /// + /// The validation to unwrap. + /// The successful value type. + /// The error type carried by the validation. + /// + /// Thrown when the validation is invalid. The exception message contains a summary of all validation errors and the + /// inner exception is an if any underlying exceptions were provided by the errors. + /// + /// + /// This is an unpure escape hatch intended for boundaries where exceptions are preferred. For external input + /// purification, continue using . + /// + public static T UnwrapOrThrow(this Validation validation) + where TError : Error => + validation.Match( + t => t, + errors => throw CreateInvalidOperationWithErrors(errors.Map(err => (Error)err))); + + private static InvalidOperationException CreateInvalidOperationWithErrors(Seq errors) + { + var baseMessage = $"Validation failed for `{typeof(T)}`"; + var errorSummary = string.Join(", ", errors.Map(e => e.Message).ToArray()); + var message = string.IsNullOrWhiteSpace(errorSummary) + ? baseMessage + : $"{baseMessage}: {errorSummary}"; + + var inner = CreateAggregateInnerException(errors); + return inner.Match( + inner => new InvalidOperationException(message, inner), + () => new InvalidOperationException(message)); + } + + private static Option CreateAggregateInnerException(Seq errors) + { + var innerExceptions = new List(); + foreach (var err in errors) + { + err.Exception.Match(x => innerExceptions.Add(x), () => { }); + } + + if (innerExceptions.Count == 0) + return Option.None; + if (innerExceptions.Count == 1) + return innerExceptions[0]; + return new AggregateException(innerExceptions); + } public static Validator AggregateValidators(this IEnumerable> validators) => t => { diff --git a/src/WalletFramework.Core/Localization/Locale.cs b/src/WalletFramework.Core/Localization/Locale.cs index a7c45ca1..661a7f4c 100644 --- a/src/WalletFramework.Core/Localization/Locale.cs +++ b/src/WalletFramework.Core/Localization/Locale.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Globalization; using LanguageExt; using Newtonsoft.Json; @@ -14,6 +15,8 @@ namespace WalletFramework.Core.Localization; /// ("en-US"). These are based on RFC 4646: https://www.rfc-editor.org/rfc/rfc4646.html. /// Locales are case-sensitive. /// +[JsonConverter(typeof(LocalJsonConverter))] +[TypeConverter(typeof(LocaleTypeConverter))] public readonly record struct Locale { private CultureInfo Value { get; } diff --git a/src/WalletFramework.Core/Localization/LocaleJsonConverters.cs b/src/WalletFramework.Core/Localization/LocaleJsonConverters.cs new file mode 100644 index 00000000..5e5b64fa --- /dev/null +++ b/src/WalletFramework.Core/Localization/LocaleJsonConverters.cs @@ -0,0 +1,60 @@ +using System.ComponentModel; +using System.Globalization; +using Newtonsoft.Json; + +namespace WalletFramework.Core.Localization; + +public sealed class LocalJsonConverter : JsonConverter +{ + public override void WriteJson(JsonWriter writer, Locale value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString()); + } + + public override Locale ReadJson(JsonReader reader, Type objectType, Locale existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + throw new JsonSerializationException("Locale cannot be null"); + + if (reader.TokenType != JsonToken.String) + throw new JsonSerializationException($"Unexpected token {reader.TokenType} when parsing Locale"); + + var s = (string)reader.Value!; + return Locale.Create(s); + } +} + +public sealed class LocaleTypeConverter : TypeConverter +{ + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) + { + return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); + } + + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + if (value is string s) + { + return Locale.Create(s); + } + + return base.ConvertFrom(context, culture, value); + } + + public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) + { + if (destinationType == typeof(string) && value is Locale locale) + { + return locale.ToString(); + } + + return base.ConvertTo(context, culture, value, destinationType); + } +} + + diff --git a/src/WalletFramework.Core/Path/JsonPath.cs b/src/WalletFramework.Core/Path/JsonPath.cs index 9c0c5b95..cc6d3ed5 100644 --- a/src/WalletFramework.Core/Path/JsonPath.cs +++ b/src/WalletFramework.Core/Path/JsonPath.cs @@ -2,7 +2,7 @@ namespace WalletFramework.Core.Path; -public readonly struct JsonPath +public readonly record struct JsonPath { private JsonPath(string path) => Value = path; diff --git a/src/WalletFramework.Core/String/StringFun.cs b/src/WalletFramework.Core/String/StringFun.cs index dfb0e4dd..be1b8286 100644 --- a/src/WalletFramework.Core/String/StringFun.cs +++ b/src/WalletFramework.Core/String/StringFun.cs @@ -3,4 +3,6 @@ namespace WalletFramework.Core.String; public static class StringFun { public static bool IsNullOrEmpty(this string? value) => string.IsNullOrEmpty(value); + + public static byte[] GetUtf8Bytes(this string value) => System.Text.Encoding.UTF8.GetBytes(value); } diff --git a/src/WalletFramework.Core/WalletFramework.Core.csproj b/src/WalletFramework.Core/WalletFramework.Core.csproj index 2a384bea..47f4f5e7 100644 --- a/src/WalletFramework.Core/WalletFramework.Core.csproj +++ b/src/WalletFramework.Core/WalletFramework.Core.csproj @@ -3,15 +3,17 @@ net8.0 enable enable + false - - - - - - - - + + + + + + + + + diff --git a/src/WalletFramework.MdocLib/DocType.cs b/src/WalletFramework.MdocLib/DocType.cs index 97ead005..e1150ec0 100644 --- a/src/WalletFramework.MdocLib/DocType.cs +++ b/src/WalletFramework.MdocLib/DocType.cs @@ -12,6 +12,8 @@ public readonly record struct DocType private DocType(string docType) => Value = docType; + public string AsString() => Value; + public override string ToString() => Value; public static implicit operator string(DocType docType) => docType.Value; diff --git a/src/WalletFramework.MdocLib/Elements/ElementIdentifier.cs b/src/WalletFramework.MdocLib/Elements/ElementIdentifier.cs index b272c933..5ee8fc2c 100644 --- a/src/WalletFramework.MdocLib/Elements/ElementIdentifier.cs +++ b/src/WalletFramework.MdocLib/Elements/ElementIdentifier.cs @@ -4,7 +4,7 @@ namespace WalletFramework.MdocLib.Elements; -public readonly struct ElementIdentifier +public readonly record struct ElementIdentifier { public string Value { get; } diff --git a/src/WalletFramework.MdocVc/ClaimDisplay.cs b/src/WalletFramework.MdocVc/ClaimDisplay.cs deleted file mode 100644 index 2fdc797a..00000000 --- a/src/WalletFramework.MdocVc/ClaimDisplay.cs +++ /dev/null @@ -1,14 +0,0 @@ -using LanguageExt; -using WalletFramework.Core.Localization; - -namespace WalletFramework.MdocVc; - -public record ClaimDisplay( - Option Name, - Option Locale); - -public static class ClaimDisplayJsonKeys -{ - public const string ClaimName = "name"; - public const string Locale = "locale"; -} diff --git a/src/WalletFramework.MdocVc/IsExternalInit.cs b/src/WalletFramework.MdocVc/IsExternalInit.cs index c6df123d..1de6d9be 100644 --- a/src/WalletFramework.MdocVc/IsExternalInit.cs +++ b/src/WalletFramework.MdocVc/IsExternalInit.cs @@ -1,3 +1,4 @@ +// ReSharper disable once CheckNamespace namespace System.Runtime.CompilerServices { // This is needed for the init property setter. diff --git a/src/WalletFramework.MdocVc/MdocCredential.cs b/src/WalletFramework.MdocVc/MdocCredential.cs new file mode 100644 index 00000000..f0080e97 --- /dev/null +++ b/src/WalletFramework.MdocVc/MdocCredential.cs @@ -0,0 +1,27 @@ +using LanguageExt; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Credentials.Abstractions; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.MdocLib; + +namespace WalletFramework.MdocVc; + +public record MdocCredential( + Mdoc Mdoc, + CredentialId CredentialId, + CredentialSetId CredentialSetId, + KeyId KeyId, + CredentialState CredentialState, + bool OneTimeUse, + Option ExpiresAt) : ICredential +{ + public CredentialId GetId() + { + return CredentialId; + } + + public CredentialSetId GetCredentialSetId() + { + return CredentialSetId; + } +} diff --git a/src/WalletFramework.MdocVc/MdocCredentialExtensions.cs b/src/WalletFramework.MdocVc/MdocCredentialExtensions.cs new file mode 100644 index 00000000..18256fc5 --- /dev/null +++ b/src/WalletFramework.MdocVc/MdocCredentialExtensions.cs @@ -0,0 +1,28 @@ +using LanguageExt; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.MdocLib; + +namespace WalletFramework.MdocVc; + +public static class MdocCredentialExtensions +{ + public static MdocCredential ToMdocCredential( + this Mdoc mdoc, + KeyId keyId, + CredentialSetId credentialSetId, + CredentialState credentialState, + bool oneTimeUse, + Option expiresAt, + CredentialId credentialId) + { + return new MdocCredential(mdoc, credentialId, credentialSetId, keyId, credentialState, oneTimeUse, expiresAt); + } + + public static string ToJsonString(this MdocCredential mdocCredential) + { + var json = JObject.FromObject(mdocCredential); + return json.ToString(); + } +} diff --git a/src/WalletFramework.MdocVc/MdocDisplay.cs b/src/WalletFramework.MdocVc/MdocDisplay.cs deleted file mode 100644 index 2ac7a929..00000000 --- a/src/WalletFramework.MdocVc/MdocDisplay.cs +++ /dev/null @@ -1,228 +0,0 @@ -using LanguageExt; -using Newtonsoft.Json.Linq; -using WalletFramework.Core.Colors; -using WalletFramework.Core.Functional; -using WalletFramework.Core.Json; -using WalletFramework.Core.Localization; -using WalletFramework.MdocLib; -using WalletFramework.MdocLib.Elements; - -namespace WalletFramework.MdocVc; - -public record MdocDisplay( - Option Logo, - Option Name, - Option BackgroundColor, - Option TextColor, - Option Locale, - Option>>> ClaimsDisplays); - -public static class MdocDisplayFun -{ - private const string LogoJsonKey = "logo"; - private const string NameJsonKey = "name"; - private const string BackgroundColorJsonKey = "background_color"; - private const string TextColorJsonKey = "text_color"; - private const string LocaleJsonKey = "locale"; - private const string ClaimsDisplaysJsonKey = "claims_displays"; - - public static Option GetByLocale(this List displays, Locale locale) - { - var dict = new Dictionary(); - foreach (var display in displays) - { - display.Locale.Match( - displayLocale => - { - dict.Add(displayLocale, display); - }, - () => - { - if (!dict.Keys.Contains(Constants.DefaultLocale)) - { - dict.Add(Constants.DefaultLocale, display); - } - } - ); - } - - if (dict.Any()) - { - return dict.FindOrDefault(locale); - } - else - { - return Option.None; - } - } - - public static JObject EncodeToJson(this MdocDisplay display) - { - var result = new JObject(); - - display.Logo.IfSome(logo => result.Add(LogoJsonKey, logo.ToString())); - display.Name.IfSome(name => result.Add(NameJsonKey, name.ToString())); - display.BackgroundColor.IfSome(color => result.Add(BackgroundColorJsonKey, color.ToString())); - display.TextColor.IfSome(color => result.Add(TextColorJsonKey, color.ToString())); - display.Locale.IfSome(locale => result.Add(LocaleJsonKey, locale.ToString())); - display.ClaimsDisplays.IfSome(claimsDisplays => - { - var claimsDict = new JObject(); - foreach (var (nameSpace, elementDict) in claimsDisplays) - { - var elements = new JObject(); - foreach (var (elementId, claimDisplays) in elementDict) - { - var displays = new JArray(); - foreach (var claimDisplay in claimDisplays) - { - var claimDisplayJson = new JObject(); - - claimDisplay.Name.IfSome( - name => claimDisplayJson.Add(ClaimDisplayJsonKeys.ClaimName, name.ToString()) - ); - - claimDisplay.Locale.IfSome( - locale => claimDisplayJson.Add(ClaimDisplayJsonKeys.Locale, locale.ToString()) - ); - - displays.Add(claimDisplayJson); - } - elements.Add(elementId.ToString(), displays); - } - claimsDict.Add(nameSpace.ToString(), elements); - } - result.Add(ClaimsDisplaysJsonKey, claimsDict); - }); - - return result; - } - - public static Option> DecodeFromJson(JArray array) - { - var result = array.TraverseAny(token => - from jObject in token.ToJObject() - select DecodeFromJson(jObject) - ).ToOption(); - - return - from displays in result - select displays.ToList(); - } - - private static MdocDisplay DecodeFromJson(JObject display) - { - var logo = - from jToken in display.GetByKey(LogoJsonKey).ToOption() - let uri = new Uri(jToken.ToString()) - select new MdocLogo(uri); - - var mdocName = - from jToken in display.GetByKey(NameJsonKey).ToOption() - from name in MdocName.OptionMdocName(jToken.ToString()) - select name; - - var backgroundColor = - from jToken in display.GetByKey(BackgroundColorJsonKey).ToOption() - from color in Color.OptionColor(jToken.ToString()) - select color; - - var textColor = - from jToken in display.GetByKey(TextColorJsonKey).ToOption() - from color in Color.OptionColor(jToken.ToString()) - select color; - - var locale = - from jToken in display.GetByKey(LocaleJsonKey).ToOption() - from l in Locale.OptionLocale(jToken.ToString()) - select l; - - var claimsDisplays = - from jToken in display.GetByKey(ClaimsDisplaysJsonKey).ToOption() - from claimsJson in jToken.ToJObject().ToOption() - from displays in DecodeClaimsDisplaysFromJson(claimsJson) - select displays; - - return new MdocDisplay(logo, mdocName, backgroundColor, textColor, locale, claimsDisplays); - } - - private static Option>>> - DecodeClaimsDisplaysFromJson(JObject namespaceDict) - { - var result = new Dictionary>>(); - - var tuples = namespaceDict.Properties().Select(prop => - { - var claimsDict = - from jObject in prop.Value.ToJObject().ToOption() - from claimsDisplays in DecodeClaimsDisplaysDictFromJson(jObject) - select claimsDisplays; - - return ( - NameSpace: NameSpace.ValidNameSpace(prop.Name).ToOption(), - ClaimsDict: claimsDict - ); - }); - - foreach (var (nameSpace, claimsDict) in tuples) - { - nameSpace.OnSome(space => claimsDict.OnSome(dictionary => - { - result.Add(space, dictionary); - return Unit.Default; - })); - } - - return result.Any() - ? result - : Option>>>.None; - } - - private static Option>> - DecodeClaimsDisplaysDictFromJson(JObject json) - { - var result = new Dictionary>(); - - var tuples = json.Properties().Select(prop => - { - var displays = - from jArray in prop.Value.ToJArray().ToOption() - from claimDisplays in jArray.TraverseAny(token => - { - var optionName = - from jToken in token.GetByKey(ClaimDisplayJsonKeys.ClaimName).ToOption() - from name in ClaimName.OptionClaimName(jToken.ToString()) - select name; - - var optionLocale = - from jToken in token.GetByKey(ClaimDisplayJsonKeys.Locale).ToOption() - from locale in Locale.OptionLocale(jToken.ToString()) - select locale; - - return - from name in optionName - from locale in optionLocale - select new ClaimDisplay(name, locale); - }) - select claimDisplays.ToList(); - - return ( - Id: ElementIdentifier.ValidElementIdentifier(prop.Name).ToOption(), - Displays: displays - ); - }); - - foreach (var (elementId, claimDisplays) in tuples) - { - elementId.OnSome(id => claimDisplays.OnSome(displays => - { - result.Add(id, displays); - return Unit.Default; - })); - } - - return result.Any() - ? result - : Option>>.None; - } -} diff --git a/src/WalletFramework.MdocVc/MdocLogo.cs b/src/WalletFramework.MdocVc/MdocLogo.cs deleted file mode 100644 index 6d42f7c6..00000000 --- a/src/WalletFramework.MdocVc/MdocLogo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using WalletFramework.Core.Uri; - -namespace WalletFramework.MdocVc; - -public readonly struct MdocLogo -{ - public MdocLogo(Uri value) - { - Value = value; - } - - private Uri Value { get; } - - public override string ToString() => Value.ToStringWithoutTrail(); - - public static implicit operator string(MdocLogo logo) => logo.ToString(); -} diff --git a/src/WalletFramework.MdocVc/MdocName.cs b/src/WalletFramework.MdocVc/MdocName.cs deleted file mode 100644 index 07cd44ff..00000000 --- a/src/WalletFramework.MdocVc/MdocName.cs +++ /dev/null @@ -1,22 +0,0 @@ -using LanguageExt; - -namespace WalletFramework.MdocVc; - -public readonly struct MdocName -{ - private string Value { get; } - - private MdocName(string value) => Value = value; - - public override string ToString() => Value; - - public static implicit operator string(MdocName mdocName) => mdocName.Value; - - public static Option OptionMdocName(string name) - { - if (string.IsNullOrWhiteSpace(name)) - return Option.None; - - return new MdocName(name); - } -} diff --git a/src/WalletFramework.MdocVc/MdocRecord.cs b/src/WalletFramework.MdocVc/MdocRecord.cs deleted file mode 100644 index 253066be..00000000 --- a/src/WalletFramework.MdocVc/MdocRecord.cs +++ /dev/null @@ -1,197 +0,0 @@ -using Hyperledger.Aries.Storage; -using Hyperledger.Aries.Storage.Models; -using LanguageExt; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Credentials.Abstractions; -using WalletFramework.Core.Cryptography.Models; -using WalletFramework.Core.Functional; -using WalletFramework.Core.Json; -using WalletFramework.MdocLib; -using static WalletFramework.MdocVc.MdocRecordFun; - -namespace WalletFramework.MdocVc; - -[JsonConverter(typeof(MdocRecordJsonConverter))] -public sealed class MdocRecord : RecordBase, ICredential -{ - public const int CurrentVersion = 2; - - public CredentialId CredentialId - { - get => CredentialId - .ValidCredentialId(Id) - .UnwrapOrThrow(new InvalidOperationException("The Id is corrupt")); - private set => Id = value; - } - - [RecordTag] - public DocType DocType => Mdoc.DocType; - - public Mdoc Mdoc { get; } - - public Option> Displays { get; } - - public KeyId KeyId { get; } - - public CredentialState CredentialState { get; } - - /// - /// Tracks whether it's a one-time use Mdoc. - /// - public bool OneTimeUse { get; set; } - - public Option ExpiresAt { get; } - - //TODO: Use CredentialSetId Type instead fo string - public string CredentialSetId - { - get => Get(); - set => Set(value, false); - } - - public override string TypeName => "WF.MdocRecord"; - - public MdocRecord( - Mdoc mdoc, - Option> displays, - KeyId keyId, - string credentialSetId, - CredentialState credentialState, - Option expiresAt, - bool isOneTimeUse = false) - { - CredentialId = CredentialId.CreateCredentialId(); - Mdoc = mdoc; - Displays = displays; - KeyId = keyId; - CredentialSetId = credentialSetId; - CredentialState = credentialState; - ExpiresAt = expiresAt; - OneTimeUse = isOneTimeUse; - RecordVersion = CurrentVersion; - } - -#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public MdocRecord() - { - } -#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - - public CredentialId GetId() => CredentialId; - - public CredentialSetId GetCredentialSetId() => Core.Credentials.CredentialSetId - .ValidCredentialSetId(CredentialSetId) - .UnwrapOrThrow(); - - public static implicit operator Mdoc(MdocRecord record) => record.Mdoc; -} - -public class MdocRecordJsonConverter : JsonConverter -{ - public override MdocRecord ReadJson( - JsonReader reader, - Type objectType, - MdocRecord? existingValue, - bool hasExistingValue, - JsonSerializer serializer) - { - var json = JObject.Load(reader); - return DecodeFromJson(json); - } - - public override void WriteJson(JsonWriter writer, MdocRecord? value, JsonSerializer serializer) - { - var json = value!.EncodeToJson(); - json.WriteTo(writer); - } -} - -public static class MdocRecordFun -{ - private const string MdocDisplaysJsonKey = "displays"; - private const string MdocJsonKey = "mdoc"; - private const string KeyIdJsonKey = "keyId"; - private const string CredentialSetIdJsonKey = "credentialSetId"; - private const string CredentialStateJsonKey = "credentialState"; - private const string ExpiresAtJsonKey = "expiresAt"; - private const string RecordVersionJsonKey = "recordVersion"; - private const string OneTimeUseJsonKey = "oneTimeUse"; - - public static MdocRecord DecodeFromJson(JObject json) - { - var id = json[nameof(RecordBase.Id)]!.ToString(); - var recordVersion = json.GetByKey(RecordVersionJsonKey).ToOption().Match( - value => value.ToObject(), - () => 1); - - var mdocStr = json[MdocJsonKey]!.ToString(); - var mdoc = Mdoc - .ValidMdoc(mdocStr) - .UnwrapOrThrow(new InvalidOperationException($"The MdocRecord with ID: {id} is corrupt")); - - var displays = - from jToken in json.GetByKey(MdocDisplaysJsonKey).ToOption() - from jArray in jToken.ToJArray().ToOption() - from mdocDisplays in MdocDisplayFun.DecodeFromJson(jArray) - select mdocDisplays; - - var keyId = KeyId - .ValidKeyId(json[KeyIdJsonKey]!.ToString()) - .UnwrapOrThrow(); - - var credentialSetId = recordVersion >= 2 ? json[CredentialSetIdJsonKey]!.ToObject()! : string.Empty; - - var expiresAt = - from expires in json.GetByKey(ExpiresAtJsonKey).ToOption() - select expires.ToObject(); - - var credentialState = recordVersion >= 2 - ? Enum.Parse(json[CredentialStateJsonKey]!.ToString()) - : CredentialState.Active; - - var oneTimeUse = json.GetByKey(OneTimeUseJsonKey).ToOption().Match( - Some: value => value.ToObject(), - None: () => false); - - var result = new MdocRecord(mdoc, displays, keyId, credentialSetId, credentialState, expiresAt, oneTimeUse) - { - Id = id, - RecordVersion = recordVersion - }; - - return result; - } - - public static JObject EncodeToJson(this MdocRecord record) - { - var result = new JObject - { - { nameof(RecordBase.Id), record.Id }, - { MdocJsonKey, record.Mdoc.Encode() }, - { KeyIdJsonKey, record.KeyId.ToString() }, - { CredentialSetIdJsonKey, record.CredentialSetId }, - { CredentialStateJsonKey, record.CredentialState.ToString() }, - { OneTimeUseJsonKey, record.OneTimeUse } - }; - - record.ExpiresAt.IfSome(expires => result.Add(ExpiresAtJsonKey, expires)); - - record.Displays.IfSome(displays => - { - var displaysJson = new JArray(); - foreach (var display in displays) - { - displaysJson.Add(display.EncodeToJson()); - } - - result.Add(MdocDisplaysJsonKey, displaysJson); - }); - - return result; - } - - public static MdocRecord ToRecord(this Mdoc mdoc, Option> displays, KeyId keyId, CredentialSetId credentialSetId, bool isOneTimeUse) => - new(mdoc, displays, keyId, credentialSetId, CredentialState.Active, Option.None, isOneTimeUse); -} diff --git a/src/WalletFramework.MdocVc/Persistence/FindMdocCredentialsWithDocType.cs b/src/WalletFramework.MdocVc/Persistence/FindMdocCredentialsWithDocType.cs new file mode 100644 index 00000000..74e1218f --- /dev/null +++ b/src/WalletFramework.MdocVc/Persistence/FindMdocCredentialsWithDocType.cs @@ -0,0 +1,15 @@ +using System.Linq.Expressions; +using WalletFramework.MdocLib; +using WalletFramework.Storage; + +namespace WalletFramework.MdocVc.Persistence; + +public record FindMdocCredentialsWithDocType : ISearchConfig +{ + public DocType DocType { get; set; } + + public Expression> ToPredicate() + { + return record => record.DocType == DocType; + } +} diff --git a/src/WalletFramework.MdocVc/Persistence/MdocCredentialRecord.cs b/src/WalletFramework.MdocVc/Persistence/MdocCredentialRecord.cs new file mode 100644 index 00000000..dc9b0cb6 --- /dev/null +++ b/src/WalletFramework.MdocVc/Persistence/MdocCredentialRecord.cs @@ -0,0 +1,37 @@ +using WalletFramework.Core.Functional; +using WalletFramework.MdocVc.Serialization; +using WalletFramework.Storage.Records; + +namespace WalletFramework.MdocVc.Persistence; + +/// +/// Storage-only model for mdoc credentials. +/// +public sealed record MdocCredentialRecord : RecordBase +{ + public string DocType { get; init; } + + public string CredentialSetId { get; init; } + + public string Serialized { get; init; } + + // Used by EF + // ReSharper disable once UnusedMember.Local +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + private MdocCredentialRecord() : base(Guid.NewGuid()) +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + { + } + + public MdocCredentialRecord(MdocCredential mdoc) : base(Guid.Parse(mdoc.CredentialId.AsString())) + { + DocType = mdoc.Mdoc.DocType.AsString(); + Serialized = MdocCredentialSerializer.Serialize(mdoc); + CredentialSetId = mdoc.CredentialSetId.AsString(); + } + + public MdocCredential ToDomainModel() + { + return MdocCredentialSerializer.Deserialize(Serialized).UnwrapOrThrow(); + } +} diff --git a/src/WalletFramework.MdocVc/Persistence/MdocCredentialRecordConfiguration.cs b/src/WalletFramework.MdocVc/Persistence/MdocCredentialRecordConfiguration.cs new file mode 100644 index 00000000..acc768d5 --- /dev/null +++ b/src/WalletFramework.MdocVc/Persistence/MdocCredentialRecordConfiguration.cs @@ -0,0 +1,18 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Records; + +namespace WalletFramework.MdocVc.Persistence; + +public sealed record MdocCredentialRecordConfiguration : IRecordConfiguration +{ + public Unit Configure(ModelBuilder modelBuilder) + { + var entity = modelBuilder.Entity(); + entity.HasIndex(r => r.DocType); + entity.HasIndex(r => r.CredentialSetId); + + return Unit.Default; + } +} + diff --git a/src/WalletFramework.MdocVc/Persistence/MdocCredentialRepository.cs b/src/WalletFramework.MdocVc/Persistence/MdocCredentialRepository.cs new file mode 100644 index 00000000..25c9d223 --- /dev/null +++ b/src/WalletFramework.MdocVc/Persistence/MdocCredentialRepository.cs @@ -0,0 +1,70 @@ +using LanguageExt; +using WalletFramework.Core.Credentials; +using WalletFramework.Storage; +using WalletFramework.Storage.Repositories; + +namespace WalletFramework.MdocVc.Persistence; + +public class MdocCredentialRepository(IRepository repository) + : IDomainRepository +{ + public async Task Add(MdocCredential domainModel) + { + var record = new MdocCredentialRecord(domainModel); + await repository.Add(record); + return Unit.Default; + } + + public async Task AddMany(IEnumerable domainModels) + { + var records = domainModels.Select(d => new MdocCredentialRecord(d)); + await repository.AddMany(records); + return Unit.Default; + } + + public virtual async Task Delete(CredentialId id) + { + var guid = Guid.Parse(id.AsString()); + await repository.RemoveById(guid); + return Unit.Default; + } + + public virtual async Task Delete(MdocCredential domainModel) + { + var record = new MdocCredentialRecord(domainModel); + await repository.Remove(record); + return Unit.Default; + } + + public async Task>> Find(ISearchConfig config) + { + var records = await repository.Find(config.ToPredicate()); + return + from credentialRecords in records + let credentials = credentialRecords.Select(r => r.ToDomainModel()) + select credentials.ToList(); + } + + public async Task> GetById(CredentialId id) + { + var guid = Guid.Parse(id.AsString()); + var record = await repository.GetById(guid); + return record.Map(r => r.ToDomainModel()); + } + + public async Task>> ListAll() + { + var records = await repository.ListAll(); + return + from credentialRecords in records + let credentials = credentialRecords.Select(r => r.ToDomainModel()) + select credentials.ToList(); + } + + public virtual async Task Update(MdocCredential domainModel) + { + var record = new MdocCredentialRecord(domainModel); + await repository.Update(record); + return Unit.Default; + } +} diff --git a/src/WalletFramework.MdocVc/Serialization/MdocCredentialSerializationConstants.cs b/src/WalletFramework.MdocVc/Serialization/MdocCredentialSerializationConstants.cs new file mode 100644 index 00000000..cfedafb7 --- /dev/null +++ b/src/WalletFramework.MdocVc/Serialization/MdocCredentialSerializationConstants.cs @@ -0,0 +1,20 @@ +namespace WalletFramework.MdocVc.Serialization; + +public static class MdocCredentialSerializationConstants +{ + public const string MdocJsonKey = "mdoc"; + + public const string CredentialIdJsonKey = "credential_id"; + + public const string CredentialSetIdJsonKey = "credential_set_id"; + + public const string DisplaysJsonKey = "displays"; + + public const string KeyIdJsonKey = "key_id"; + + public const string CredentialStateJsonKey = "credential_state"; + + public const string OneTimeUseJsonKey = "one_time_use"; + + public const string ExpiresAtJsonKey = "expires_at"; +} diff --git a/src/WalletFramework.MdocVc/Serialization/MdocCredentialSerializer.cs b/src/WalletFramework.MdocVc/Serialization/MdocCredentialSerializer.cs new file mode 100644 index 00000000..dbddc848 --- /dev/null +++ b/src/WalletFramework.MdocVc/Serialization/MdocCredentialSerializer.cs @@ -0,0 +1,78 @@ +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Functional; +using WalletFramework.Core.Json; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.MdocLib; +using static WalletFramework.MdocVc.Serialization.MdocCredentialSerializationConstants; + +namespace WalletFramework.MdocVc.Serialization; + +public static class MdocCredentialSerializer +{ + public static string Serialize(MdocCredential credential) + { + var json = EncodeToJObject(credential); + return json.ToString(); + } + + public static Validation Deserialize(string jsonString) + { + var json = JObject.Parse(jsonString); + return DecodeFromJObject(json); + } + + private static JObject EncodeToJObject(this MdocCredential credential) + { + var result = new JObject + { + { MdocJsonKey, credential.Mdoc.Encode() }, + { CredentialIdJsonKey, credential.CredentialId.AsString() }, + { CredentialSetIdJsonKey, credential.CredentialSetId.AsString() }, + { KeyIdJsonKey, credential.KeyId.AsString() }, + { CredentialStateJsonKey, credential.CredentialState.ToString() }, + { OneTimeUseJsonKey, credential.OneTimeUse } + }; + + credential.ExpiresAt.IfSome(expires => result.Add(ExpiresAtJsonKey, expires)); + + return result; + } + + private static MdocCredential DecodeFromJObject(JObject json) + { + var mdocStr = json[MdocJsonKey]!.ToString(); + var mdoc = Mdoc.ValidMdoc(mdocStr).UnwrapOrThrow(); + + var credentialId = CredentialId + .ValidCredentialId(json[CredentialIdJsonKey]!.ToString()) + .UnwrapOrThrow(); + + var credentialSetId = CredentialSetId + .ValidCredentialSetId(json[CredentialSetIdJsonKey]!.ToString()) + .UnwrapOrThrow(); + + var keyId = KeyId + .ValidKeyId(json[KeyIdJsonKey]!.ToString()) + .UnwrapOrThrow(); + + var credentialState = Enum.Parse(json[CredentialStateJsonKey]!.ToString()); + + var oneTimeUse = json.GetByKey(OneTimeUseJsonKey).ToOption().Match( + Some: value => value.ToObject(), + None: () => false); + + var expiresAt = + from ex in json.GetByKey(ExpiresAtJsonKey).ToOption() + select ex.ToObject(); + + return new MdocCredential( + mdoc, + credentialId, + credentialSetId, + keyId, + credentialState, + oneTimeUse, + expiresAt); + } +} diff --git a/src/WalletFramework.MdocVc/WalletFramework.MdocVc.csproj b/src/WalletFramework.MdocVc/WalletFramework.MdocVc.csproj index 5687023c..6f2ce23a 100644 --- a/src/WalletFramework.MdocVc/WalletFramework.MdocVc.csproj +++ b/src/WalletFramework.MdocVc/WalletFramework.MdocVc.csproj @@ -3,10 +3,11 @@ net8.0 enable enable + false - + diff --git a/src/WalletFramework.Oid4Vc/Credential/CredentialFun.cs b/src/WalletFramework.Oid4Vc/Credential/CredentialFun.cs index 85e4aea8..acb3f43f 100644 --- a/src/WalletFramework.Oid4Vc/Credential/CredentialFun.cs +++ b/src/WalletFramework.Oid4Vc/Credential/CredentialFun.cs @@ -1,10 +1,9 @@ using OneOf; using WalletFramework.Core.Credentials.Abstractions; -using WalletFramework.Core.Functional; using WalletFramework.MdocLib; using WalletFramework.MdocVc; +using WalletFramework.SdJwtVc; using WalletFramework.SdJwtVc.Models; -using WalletFramework.SdJwtVc.Models.Records; namespace WalletFramework.Oid4Vc.Credential; @@ -12,15 +11,12 @@ public static class CredentialFun { public static OneOf GetCredentialType(this ICredential credential) { - switch (credential) + return credential switch { - case SdJwtRecord sdJwt: - return Vct.ValidVct(sdJwt.Vct).UnwrapOrThrow(); - case MdocRecord mdoc: - return mdoc.DocType; - default: - throw new InvalidOperationException("Invalid credential type"); - } + SdJwtCredential sdJwt => sdJwt.Vct, + MdocCredential mdoc => mdoc.Mdoc.DocType, + _ => throw new InvalidOperationException("Invalid credential type") + }; } public static string GetCredentialTypeAsString(this ICredential credential) @@ -35,8 +31,8 @@ public static bool SupportsKeyBinding(this ICredential credential) { return credential switch { - SdJwtRecord sdJwt => sdJwt.KeyId.IsSome, - MdocRecord => true, + SdJwtCredential sdJwt => sdJwt.KeyId.IsSome, + MdocCredential => true, _ => throw new InvalidOperationException("Invalid credential type") }; } diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/CredentialDataSetExtensions.cs b/src/WalletFramework.Oid4Vc/CredentialSet/CredentialDataSetExtensions.cs new file mode 100644 index 00000000..c3f284da --- /dev/null +++ b/src/WalletFramework.Oid4Vc/CredentialSet/CredentialDataSetExtensions.cs @@ -0,0 +1,16 @@ +using WalletFramework.Oid4Vc.CredentialSet.Models; + +namespace WalletFramework.Oid4Vc.CredentialSet; + +public static class CredentialDataSetExtensions +{ + public static bool IsExpired(this CredentialDataSet credentialDataSet) => + credentialDataSet.ExpiresAt.Match( + expiresAt => expiresAt < DateTime.UtcNow, + () => false); + + public static bool IsRevoked(this CredentialDataSet credentialDataSet) => + credentialDataSet.RevokedAt.Match( + revokedAt => revokedAt < DateTime.UtcNow, + () => false); +} diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetService.cs b/src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetService.cs index 3210953a..174313a8 100644 --- a/src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetService.cs +++ b/src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetService.cs @@ -1,48 +1,50 @@ -using Hyperledger.Aries.Storage; -using LanguageExt; using WalletFramework.Core.Credentials; using WalletFramework.Core.StatusList; using WalletFramework.Oid4Vc.CredentialSet.Models; +using WalletFramework.Oid4Vc.CredentialSet.Persistence; +using WalletFramework.Storage; namespace WalletFramework.Oid4Vc.CredentialSet; public class CredentialSetService( - ICredentialSetStorage storage, + IDomainRepository credentialSetRepository, IStatusListService statusListService) : ICredentialSetService { - public async Task RefreshCredentialSetState(CredentialSetRecord credentialSetRecord) + public async Task RefreshCredentialSetState(CredentialDataSet credentialDataSet) { - var oldState = credentialSetRecord.State; + var oldState = credentialDataSet.State; - if (credentialSetRecord.IsDeleted()) - return credentialSetRecord; + if (credentialDataSet.DeletedAt.IsSome) + return credentialDataSet; - credentialSetRecord.ExpiresAt.IfSome(expiresAt => + credentialDataSet.ExpiresAt.IfSome(expiresAt => { if (expiresAt < DateTime.UtcNow) - credentialSetRecord.State = CredentialState.Expired; + { + credentialDataSet = credentialDataSet with { State = CredentialState.Expired }; + } }); - await credentialSetRecord.StatusListEntry.IfSomeAsync( + await credentialDataSet.StatusListEntry.IfSomeAsync( async statusList => { await statusListService.GetState(statusList).IfSomeAsync( state => { if (state == CredentialState.Revoked) - credentialSetRecord.State = CredentialState.Revoked; + credentialDataSet = credentialDataSet with { State = CredentialState.Revoked }; }); }); - if (oldState != credentialSetRecord.State) - await storage.Update(credentialSetRecord); + if (oldState != credentialDataSet.State) + await credentialSetRepository.Update(credentialDataSet); - return credentialSetRecord; + return credentialDataSet; } public async Task RefreshCredentialSetStates() { - var credentialSetRecords = await storage.List(Option.None); + var credentialSetRecords = await credentialSetRepository.ListAll(); await credentialSetRecords.IfSomeAsync( async records => diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetStorage.cs b/src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetStorage.cs deleted file mode 100644 index 92e64e98..00000000 --- a/src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetStorage.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Hyperledger.Aries; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; -using LanguageExt; -using WalletFramework.Core.Credentials; -using WalletFramework.Oid4Vc.CredentialSet.Models; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; -using WalletFramework.Core.Functional; - -namespace WalletFramework.Oid4Vc.CredentialSet; - -public class CredentialSetStorage( - IAgentProvider agentProvider, - ISdJwtVcHolderService sdJwtVcHolderService, - IMdocStorage mDocStorage, - IWalletRecordService walletRecordService) : ICredentialSetStorage -{ - public async Task Add(CredentialSetRecord credentialSetRecord) - { - var context = await agentProvider.GetContextAsync(); - await walletRecordService.AddAsync(context.Wallet, credentialSetRecord); - } - - public virtual async Task Delete(CredentialSetId credentialSetId) - { - var context = await agentProvider.GetContextAsync(); - var credentialSetRecord = - await walletRecordService.GetAsync(context.Wallet, credentialSetId); - if (credentialSetRecord == null) - throw new AriesFrameworkException(ErrorCode.RecordNotFound, "CredentialSet record not found"); - - var sdJwtRecords = await sdJwtVcHolderService.ListAsync(context, credentialSetId); - await sdJwtRecords.Match( - Some: async records => - { - foreach (var record in records) - await sdJwtVcHolderService.DeleteAsync(context, record.Id); - }, - None: () => Task.CompletedTask); - - var mDocRecords = await mDocStorage.List(credentialSetId); - await mDocRecords.Match( - Some: async records => - { - foreach (var record in records) - await mDocStorage.Delete(record); - }, - None: () => Task.CompletedTask); - - credentialSetRecord.State = CredentialState.Deleted; - credentialSetRecord.DeletedAt = DateTime.UtcNow; - await walletRecordService.UpdateAsync(context.Wallet, credentialSetRecord); - } - - public async Task> Get(CredentialSetId credentialSetId) - { - var context = await agentProvider.GetContextAsync(); - var record = await walletRecordService.GetAsync(context.Wallet, credentialSetId); - - return record; - } - - public async Task>> List( - Option query, - int count = 100, - int skip = 0) - { - var context = await agentProvider.GetContextAsync(); - var records = await walletRecordService.SearchAsync( - context.Wallet, - query.ToNullable(), - null, - count, - skip); - - if (records.Count == 0) - return Option>.None; - - return records; - } - - - public virtual async Task Update(CredentialSetRecord credentialSetRecord) - { - var context = await agentProvider.GetContextAsync(); - await walletRecordService.UpdateAsync(context.Wallet, credentialSetRecord); - } -} diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/ICredentialSetService.cs b/src/WalletFramework.Oid4Vc/CredentialSet/ICredentialSetService.cs index dd3201f9..83e446b1 100644 --- a/src/WalletFramework.Oid4Vc/CredentialSet/ICredentialSetService.cs +++ b/src/WalletFramework.Oid4Vc/CredentialSet/ICredentialSetService.cs @@ -4,7 +4,7 @@ namespace WalletFramework.Oid4Vc.CredentialSet; public interface ICredentialSetService { - Task RefreshCredentialSetState(CredentialSetRecord credentialSetRecord); + Task RefreshCredentialSetState(CredentialDataSet credentialDataSet); Task RefreshCredentialSetStates(); } diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/ICredentialSetStorage.cs b/src/WalletFramework.Oid4Vc/CredentialSet/ICredentialSetStorage.cs deleted file mode 100644 index 9f82f87a..00000000 --- a/src/WalletFramework.Oid4Vc/CredentialSet/ICredentialSetStorage.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Hyperledger.Aries.Storage; -using LanguageExt; -using WalletFramework.Core.Credentials; -using WalletFramework.Oid4Vc.CredentialSet.Models; - -namespace WalletFramework.Oid4Vc.CredentialSet; - -public interface ICredentialSetStorage -{ - Task Delete(CredentialSetId credentialSetId); - - Task> Get( - CredentialSetId credentialSetId); - - Task Add(CredentialSetRecord credentialSetRecord); - - Task Update(CredentialSetRecord credentialSetRecord); - - Task>> List( - Option query, - int count = 100, - int skip = 0); -} diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/Models/CredentialDataSet.cs b/src/WalletFramework.Oid4Vc/CredentialSet/Models/CredentialDataSet.cs new file mode 100644 index 00000000..b7e1a0c8 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/CredentialSet/Models/CredentialDataSet.cs @@ -0,0 +1,110 @@ +using LanguageExt; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Credentials.Abstractions; +using WalletFramework.Core.Functional; +using WalletFramework.Core.StatusList; +using WalletFramework.MdocLib; +using WalletFramework.MdocVc; +using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Models; + +namespace WalletFramework.Oid4Vc.CredentialSet.Models; + +public sealed record CredentialDataSet( + CredentialSetId CredentialSetId, + Option SdJwtCredentialType, + Option MDocCredentialType, + Dictionary CredentialAttributes, + CredentialState State, + Option StatusListEntry, + Option ExpiresAt, + Option IssuedAt, + Option NotBefore, + Option RevokedAt, + Option DeletedAt, + string IssuerId) +{ + public static CredentialDataSet FromCredentials(IEnumerable credentials, Option issuerIdHint) + { + var credentialArray = credentials as ICredential[] ?? credentials.ToArray(); + + if (credentialArray.Length == 0) + throw new ArgumentException("No credentials provided", nameof(credentials)); + + var setId = credentialArray[0].GetCredentialSetId(); + + var distinctSetIds = credentialArray + .Select(c => c.GetCredentialSetId()) + .Distinct() + .ToArray(); + + if (distinctSetIds.Length > 1) + throw new InvalidOperationException("All credentials must belong to the same credential set."); + + var sdJwtType = Option.None; + var mdocType = Option.None; + + var attributes = new Dictionary(); + + var state = CredentialState.Active; + var statusListEntry = Option.None; + var expiresAt = Option.None; + var issuedAt = Option.None; + var notBefore = Option.None; + var revokedAt = Option.None; + var deletedAt = Option.None; + var issuerId = string.Empty; + + foreach (var credential in credentialArray) + { + switch (credential) + { + case SdJwtCredential sdJwtCredential: + sdJwtType = sdJwtCredential.Vct; + attributes = sdJwtCredential.Claims; + state = sdJwtCredential.CredentialState; + expiresAt = sdJwtCredential.ExpiresAt; + issuedAt = sdJwtCredential.IssuedAt; + notBefore = sdJwtCredential.NotBefore; + statusListEntry = sdJwtCredential.StatusListEntry; + break; + + case MdocCredential mdocCredential: + mdocType = mdocCredential.Mdoc.DocType; + state = mdocCredential.CredentialState; + if (attributes.Count == 0) + { + attributes = mdocCredential.Mdoc.IssuerSigned.IssuerNameSpaces.Value + .First().Value + .ToDictionary( + issuerSignedItem => issuerSignedItem.ElementId.ToString(), + issuerSignedItem => issuerSignedItem.Element.ToString()); + } + + if (expiresAt.IsNone) + expiresAt = mdocCredential.ExpiresAt; + break; + + default: + throw new InvalidOperationException("Unknown credential implementation"); + } + } + + if (string.IsNullOrWhiteSpace(issuerId)) + issuerId = issuerIdHint.Fallback(string.Empty); + + return new CredentialDataSet( + setId, + sdJwtType, + mdocType, + attributes, + state, + statusListEntry, + expiresAt, + issuedAt, + notBefore, + revokedAt, + deletedAt, + issuerId); + } +} diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/Models/CredentialSetRecord.cs b/src/WalletFramework.Oid4Vc/CredentialSet/Models/CredentialSetRecord.cs deleted file mode 100644 index 7edfe7fa..00000000 --- a/src/WalletFramework.Oid4Vc/CredentialSet/Models/CredentialSetRecord.cs +++ /dev/null @@ -1,295 +0,0 @@ -using Hyperledger.Aries.Storage; -using LanguageExt; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using OneOf; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Functional; -using WalletFramework.Core.Json; -using WalletFramework.Core.StatusList; -using WalletFramework.Core.String; -using WalletFramework.MdocLib; -using WalletFramework.MdocVc; -using WalletFramework.Oid4Vc.Oid4Vci.Issuer.Models; -using WalletFramework.SdJwtVc.Models; -using WalletFramework.SdJwtVc.Models.Records; -using CredentialState = WalletFramework.Core.Credentials.CredentialState; - -namespace WalletFramework.Oid4Vc.CredentialSet.Models; - -[JsonConverter(typeof(CredentialSetRecordConverter))] -public sealed class CredentialSetRecord : RecordBase -{ - public CredentialSetId CredentialSetId => CredentialSetId - .ValidCredentialSetId(Id) - .UnwrapOrThrow(new InvalidOperationException("The Id is corrupt")); - - public Option SdJwtCredentialType { get; set; } - - public Option MDocCredentialType { get; set; } - - public Dictionary CredentialAttributes { get; set; } = new(); - - public CredentialState State { get; set; } - - public Option NotBefore { get; set; } - - public Option IssuedAt { get; set; } - - public Option ExpiresAt { get; set; } - - public Option StatusListEntry { get; set; } - - public Option RevokedAt { get; set; } - - public Option DeletedAt { get; set; } - - [JsonIgnore] - public string IssuerId - { - get => Get(); - set => Set(value, false); - } - - /// - public override string TypeName => "AF.CredentialSetRecord"; - - public CredentialSetRecord( - Option sdJwtCredentialType, - Option mDocCredentialType, - Dictionary credentialAttributes, - CredentialState credentialState, - Option statusListEntry, - Option expiresAt, - Option issuedAt, - Option notBefore, - Option revokedAt, - Option deletedAt, - Option createdAt, - Option updatedAt, - string issuerId) - { - SdJwtCredentialType = sdJwtCredentialType; - MDocCredentialType = mDocCredentialType; - CredentialAttributes = credentialAttributes; - State = credentialState; - StatusListEntry = statusListEntry; - ExpiresAt = expiresAt; - IssuedAt = issuedAt; - NotBefore = notBefore; - RevokedAt = revokedAt; - DeletedAt = deletedAt; - UpdatedAtUtc = updatedAt.ToNullable(); - CreatedAtUtc = createdAt.ToNullable(); - IssuerId = issuerId; - } - - public CredentialSetRecord() - { - Id = CredentialSetId.CreateCredentialSetId(); - CreatedAtUtc = DateTime.UtcNow; - UpdatedAtUtc = DateTime.UtcNow; - } -} - -public class CredentialSetRecordConverter : JsonConverter -{ - public override void WriteJson(JsonWriter writer, CredentialSetRecord? value, JsonSerializer serializer) - { - var json = value!.EncodeToJson(); - json.WriteTo(writer); - } - - public override CredentialSetRecord ReadJson( - JsonReader reader, - Type objectType, - CredentialSetRecord? existingValue, - bool hasExistingValue, - JsonSerializer serializer) - { - var json = JObject.Load(reader); - return CredentialSetRecordExtensions.DecodeFromJson(json); - } -} - -public static class CredentialSetRecordExtensions -{ - private const string CredentialSetIdTypeJsonKey = "credential_set_id"; - private const string SdJwtCredentialTypeJsonKey = "sd_jwt_credential_type"; - private const string MDocCredentialTypeJsonKey = "mdoc_credential_type"; - private const string CredentialAttributesJsonKey = "credential_attributes"; - private const string StateJsonKey = "state"; - private const string ExpiresAtJsonKey = "expires_at"; - private const string IssuedAtJsonKey = "issued_at"; - private const string NotBeforeJsonKey = "not_before"; - private const string RevokedAtJsonKey = "revoked_at"; - private const string DeletedAtJsonKey = "deleted_at"; - private const string IssuerIdJsonKey = "issuer_id"; - private const string CreatedAtJsonKey = "created_at"; - private const string UpdatedAtJsonKey = "updated_at"; - private const string StatusListJsonKey = "status_list"; - - public static void AddSdJwtData( - this CredentialSetRecord credentialSetRecord, - SdJwtRecord sdJwtRecord) - { - credentialSetRecord.SdJwtCredentialType = Vct.ValidVct(sdJwtRecord.Vct).ToOption(); - credentialSetRecord.CredentialAttributes = sdJwtRecord.Claims; - credentialSetRecord.State = sdJwtRecord.CredentialState; - credentialSetRecord.ExpiresAt = sdJwtRecord.ExpiresAt.ToOption(); - credentialSetRecord.IssuedAt = sdJwtRecord.IssuedAt.ToOption(); - credentialSetRecord.NotBefore = sdJwtRecord.NotBefore.ToOption(); - credentialSetRecord.IssuerId = sdJwtRecord.IssuerId; - credentialSetRecord.StatusListEntry = sdJwtRecord.StatusListEntry; - } - - internal static void AddMdocData( - this CredentialSetRecord credentialSetRecord, - MdocRecord mdocRecord) - { - credentialSetRecord.MDocCredentialType = mdocRecord.DocType; - credentialSetRecord.State = mdocRecord.CredentialState; - - if (credentialSetRecord.CredentialAttributes.Count == 0) - credentialSetRecord.CredentialAttributes = mdocRecord.Mdoc.IssuerSigned.IssuerNameSpaces.Value.First().Value.ToDictionary( - issuerSignedItem => issuerSignedItem.ElementId.ToString(), - issuerSignedItem => issuerSignedItem.Element.ToString()); - - if (credentialSetRecord.ExpiresAt.IsNone) - credentialSetRecord.ExpiresAt = mdocRecord.ExpiresAt.ToOption(); - } - - public static void AddMDocData( - this CredentialSetRecord credentialSetRecord, - MdocRecord mdocRecord, - CredentialIssuerId credentialIssuerId) - { - AddMdocData(credentialSetRecord, mdocRecord); - - if (credentialSetRecord.IssuerId.IsNullOrEmpty()) - credentialSetRecord.IssuerId = credentialIssuerId.ToString(); - } - - public static OneOf GetCredentialType(this CredentialSetRecord credentialSetRecord) - { - return credentialSetRecord.SdJwtCredentialType.Match( - vct => vct, - () => credentialSetRecord.MDocCredentialType.Match>( - docType => docType, - () => throw new InvalidOperationException("No credential type found"))); - } - - public static bool IsActive(this CredentialSetRecord credentialSetRecord) => - credentialSetRecord.State == CredentialState.Active; - - public static bool IsRevoked(this CredentialSetRecord credentialSetRecord) => - credentialSetRecord.State == CredentialState.Revoked; - - public static bool IsDeleted(this CredentialSetRecord credentialSetRecord) => - credentialSetRecord.State == CredentialState.Deleted; - - public static bool IsExpired(this CredentialSetRecord credentialSetRecord) => - credentialSetRecord.State == CredentialState.Expired; - - public static JObject EncodeToJson(this CredentialSetRecord credentialSetRecord) - { - var result = new JObject(); - - result.Add(nameof(RecordBase.Id), credentialSetRecord.Id); - - credentialSetRecord.SdJwtCredentialType.IfSome(vct => result.Add(SdJwtCredentialTypeJsonKey, vct.ToString())); - credentialSetRecord.MDocCredentialType.IfSome(docType => result.Add(MDocCredentialTypeJsonKey, docType.ToString())); - - var jObjectDictionary = new JObject(); - foreach (var kvp in credentialSetRecord.CredentialAttributes) - { - jObjectDictionary.Add(kvp.Key, kvp.Value); - } - result.Add(CredentialAttributesJsonKey, jObjectDictionary); - - result.Add(StateJsonKey, credentialSetRecord.State.ToString()); - - credentialSetRecord.ExpiresAt.IfSome(expiresAt => result.Add(ExpiresAtJsonKey, expiresAt)); - credentialSetRecord.IssuedAt.IfSome(issuedAt => result.Add(IssuedAtJsonKey, issuedAt)); - credentialSetRecord.NotBefore.IfSome(notBefore => result.Add(NotBeforeJsonKey, notBefore)); - credentialSetRecord.RevokedAt.IfSome(revokedAt => result.Add(RevokedAtJsonKey, revokedAt)); - credentialSetRecord.DeletedAt.IfSome(deletedAt => result.Add(DeletedAtJsonKey, deletedAt)); - credentialSetRecord.CreatedAtUtc.IfSome(createdAtUtc => result.Add(CreatedAtJsonKey, createdAtUtc)); - credentialSetRecord.UpdatedAtUtc.IfSome(updatedAtUtc => result.Add(UpdatedAtJsonKey, updatedAtUtc)); - credentialSetRecord.StatusListEntry.IfSome(statusList => result.Add(StatusListJsonKey, JObject.FromObject(statusList))); - result.Add(IssuerIdJsonKey, credentialSetRecord.IssuerId); - - return result; - } - - public static CredentialSetRecord DecodeFromJson(JObject json) - { - var id = json[nameof(RecordBase.Id)]!.ToString(); - - var sdJwtCredentialType = - from jToken in json.GetByKey(SdJwtCredentialTypeJsonKey).ToOption() - from vct in Vct.ValidVct(jToken).ToOption() - select vct; - - var mDocCredentialType = - from jToken in json.GetByKey(MDocCredentialTypeJsonKey).ToOption() - from docType in DocType.ValidDoctype(jToken).ToOption() - select docType; - - var credentialAttributesType = json[CredentialAttributesJsonKey]!.ToObject>()!; - - var stateType = Enum.Parse(json[StateJsonKey]!.ToString()); - - var statusListType = - from jToken in json.GetByKey(StatusListJsonKey).ToOption() - select jToken.ToObject(); - - var expiresAtType = - from jToken in json.GetByKey(ExpiresAtJsonKey).ToOption() - select jToken.ToObject(); - - var issuedAtType = - from jToken in json.GetByKey(IssuedAtJsonKey).ToOption() - select jToken.ToObject(); - - var notBeforeType = - from jToken in json.GetByKey(NotBeforeJsonKey).ToOption() - select jToken.ToObject(); - - var revokedAtType = - from jToken in json.GetByKey(RevokedAtJsonKey).ToOption() - select jToken.ToObject(); - - var deletedAtType = - from jToken in json.GetByKey(DeletedAtJsonKey).ToOption() - select jToken.ToObject(); - - var createdAtType = - from jToken in json.GetByKey(CreatedAtJsonKey).ToOption() - select jToken.ToObject(); - - var updatedAtType = - from jToken in json.GetByKey(UpdatedAtJsonKey).ToOption() - select jToken.ToObject(); - - var issuerIdentifierType = json[IssuerIdJsonKey]!.ToString(); - - return new CredentialSetRecord( - sdJwtCredentialType, - mDocCredentialType, - credentialAttributesType, - stateType, - statusListType, - expiresAtType, - issuedAtType, - notBeforeType, - revokedAtType, - deletedAtType, - createdAtType, - updatedAtType, - issuerIdentifierType) - { - Id = id - }; - } -} diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/Models/OnDemandCredentialSet.cs b/src/WalletFramework.Oid4Vc/CredentialSet/Models/OnDemandCredentialSet.cs index 91d176cc..06708ab4 100644 --- a/src/WalletFramework.Oid4Vc/CredentialSet/Models/OnDemandCredentialSet.cs +++ b/src/WalletFramework.Oid4Vc/CredentialSet/Models/OnDemandCredentialSet.cs @@ -2,4 +2,4 @@ namespace WalletFramework.Oid4Vc.CredentialSet.Models; -public record OnDemandCredentialSet(CredentialSetRecord CredentialSetRecord, List CredentialRecords); +public record OnDemandCredentialSet(CredentialDataSet CredentialDataSet, List Credentials); diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRecord.cs b/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRecord.cs new file mode 100644 index 00000000..9c48be4b --- /dev/null +++ b/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRecord.cs @@ -0,0 +1,115 @@ +using LanguageExt; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Functional; +using WalletFramework.Core.StatusList; +using WalletFramework.MdocLib; +using WalletFramework.Oid4Vc.CredentialSet.Models; +using WalletFramework.SdJwtVc.Models; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Oid4Vc.CredentialSet.Persistence; + +public sealed record CredentialDataSetRecord : RecordBase +{ + public string? SdJwtCredentialType { get; init; } + + public string? MDocCredentialType { get; init; } + + public string AttributesJson { get; init; } + + public string State { get; init; } + + public DateTime? NotBefore { get; init; } + + public DateTime? IssuedAt { get; init; } + + public DateTime? ExpiresAt { get; init; } + + public string? StatusListJson { get; init; } + + public DateTime? RevokedAt { get; init; } + + public DateTime? DeletedAt { get; init; } + + public string IssuerId { get; init; } + + // Used by EF +#pragma warning disable CS8618 + // ReSharper disable once UnusedMember.Local + private CredentialDataSetRecord() : base(Guid.NewGuid()) + { + } +#pragma warning restore CS8618 + + public CredentialDataSetRecord(CredentialDataSet domain) : base(Guid.Parse(domain.CredentialSetId.AsString())) + { + SdJwtCredentialType = + (from v in domain.SdJwtCredentialType + select v.ToString()).ToNullable(); + + MDocCredentialType = + (from d in domain.MDocCredentialType + select d.ToString()).ToNullable(); + + AttributesJson = JsonConvert.SerializeObject(domain.CredentialAttributes); + State = domain.State.ToString(); + NotBefore = domain.NotBefore.ToNullable(); + IssuedAt = domain.IssuedAt.ToNullable(); + ExpiresAt = domain.ExpiresAt.ToNullable(); + + StatusListJson = + (from x in domain.StatusListEntry + select JsonConvert.SerializeObject(x)).ToNullable(); + + RevokedAt = domain.RevokedAt.ToNullable(); + DeletedAt = domain.DeletedAt.ToNullable(); + IssuerId = domain.IssuerId; + } + + public CredentialDataSet ToDomainModel() + { + var setId = CredentialSetId.ValidCredentialSetId(RecordId.ToString()).UnwrapOrThrow(); + + var sdJwtType = string.IsNullOrWhiteSpace(SdJwtCredentialType) + ? Option.None + : Vct.ValidVct(SdJwtCredentialType!).ToOption(); + + var mdocType = string.IsNullOrWhiteSpace(MDocCredentialType) + ? Option.None + : DocType.ValidDoctype(new JValue(MDocCredentialType!)).ToOption(); + + var attributes = JsonConvert.DeserializeObject>(AttributesJson) + ?? []; + + var state = Enum.Parse(State); + + Option statusList; + if (string.IsNullOrWhiteSpace(StatusListJson)) + { + statusList = Option.None; + } + else + { + var statusListObject = JObject.Parse(StatusListJson!); + var normalizedStatusListObject = new JObject( + statusListObject.Properties().Select(prop => new JProperty(prop.Name.ToLowerInvariant(), prop.Value))); + statusList = StatusListEntry.FromJObject(normalizedStatusListObject).ToOption(); + } + + return new CredentialDataSet( + setId, + sdJwtType, + mdocType, + attributes, + state, + statusList, + ExpiresAt.ToOption(), + IssuedAt.ToOption(), + NotBefore.ToOption(), + RevokedAt.ToOption(), + DeletedAt.ToOption(), + IssuerId); + } +} diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRecordConfiguration.cs b/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRecordConfiguration.cs new file mode 100644 index 00000000..bb0397a1 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRecordConfiguration.cs @@ -0,0 +1,17 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Oid4Vc.CredentialSet.Persistence; + +public sealed record CredentialDataSetRecordConfiguration : IRecordConfiguration +{ + public Unit Configure(ModelBuilder modelBuilder) + { + var entity = modelBuilder.Entity(); + entity.HasIndex(r => r.IssuerId); + entity.HasIndex(r => r.SdJwtCredentialType); + entity.HasIndex(r => r.MDocCredentialType); + return Unit.Default; + } +} diff --git a/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRepository.cs b/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRepository.cs new file mode 100644 index 00000000..e814d6c7 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/CredentialSet/Persistence/CredentialDataSetRepository.cs @@ -0,0 +1,69 @@ +using LanguageExt; +using WalletFramework.Core.Credentials; +using WalletFramework.Oid4Vc.CredentialSet.Models; +using WalletFramework.Storage; +using WalletFramework.Storage.Repositories; + +namespace WalletFramework.Oid4Vc.CredentialSet.Persistence; + +public class CredentialDataSetRepository(IRepository repository) + : IDomainRepository +{ + public virtual async Task Add(CredentialDataSet domainModel) + { + return await (await GetById(domainModel.CredentialSetId)).Match( + async credential => await Update(domainModel), + async () => + { + var record = new CredentialDataSetRecord(domainModel); + return await repository.Add(record); + }); + } + + public virtual async Task AddMany(IEnumerable domainModels) + { + var records = domainModels.Select(domain => new CredentialDataSetRecord(domain)); + await repository.AddMany(records); + return Unit.Default; + } + + public virtual async Task Delete(CredentialSetId id) + { + var guid = Guid.Parse(id.AsString()); + await repository.RemoveById(guid); + return Unit.Default; + } + + public virtual async Task>> Find(ISearchConfig config) + { + var records = await repository.Find(config.ToPredicate()); + return from rs in records select rs.Select(r => r.ToDomainModel()).ToList(); + } + + public virtual async Task> GetById(CredentialSetId id) + { + var guid = Guid.Parse(id.AsString()); + var record = await repository.GetById(guid); + return record.Map(r => r.ToDomainModel()); + } + + public virtual async Task>> ListAll() + { + var records = await repository.ListAll(); + return from rs in records select rs.Select(r => r.ToDomainModel()).ToList(); + } + + public virtual async Task Update(CredentialDataSet domainModel) + { + var record = new CredentialDataSetRecord(domainModel); + await repository.Update(record); + return Unit.Default; + } + + public virtual async Task Delete(CredentialDataSet domainModel) + { + var record = new CredentialDataSetRecord(domainModel); + await repository.Remove(record); + return Unit.Default; + } +} diff --git a/src/WalletFramework.Oid4Vc/Database/Migration/Abstraction/IMigrationStepsProvider.cs b/src/WalletFramework.Oid4Vc/Database/Migration/Abstraction/IMigrationStepsProvider.cs deleted file mode 100644 index b21a9f49..00000000 --- a/src/WalletFramework.Oid4Vc/Database/Migration/Abstraction/IMigrationStepsProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace WalletFramework.Oid4Vc.Database.Migration.Abstraction; - -public interface IMigrationStepsProvider -{ - public IEnumerable Get(); -} diff --git a/src/WalletFramework.Oid4Vc/Database/Migration/Abstraction/IRecordsMigrationService.cs b/src/WalletFramework.Oid4Vc/Database/Migration/Abstraction/IRecordsMigrationService.cs deleted file mode 100644 index b5a79271..00000000 --- a/src/WalletFramework.Oid4Vc/Database/Migration/Abstraction/IRecordsMigrationService.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace WalletFramework.Oid4Vc.Database.Migration.Abstraction; - -public interface IRecordsMigrationService -{ - public Task Migrate(); - - public IEnumerable AddMigrationStep(MigrationStep migrationStep); - - public IEnumerable AddMigrationSteps(IEnumerable steps); - - public IEnumerable GetMigrationSteps(); -} diff --git a/src/WalletFramework.Oid4Vc/Database/Migration/Implementations/MigrationStepsProvider.cs b/src/WalletFramework.Oid4Vc/Database/Migration/Implementations/MigrationStepsProvider.cs deleted file mode 100644 index 12dd1411..00000000 --- a/src/WalletFramework.Oid4Vc/Database/Migration/Implementations/MigrationStepsProvider.cs +++ /dev/null @@ -1,227 +0,0 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; -using LanguageExt; -using LanguageExt.UnsafeValueAccess; -using OneOf; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Functional; -using WalletFramework.MdocVc; -using WalletFramework.Oid4Vc.CredentialSet; -using WalletFramework.Oid4Vc.CredentialSet.Models; -using WalletFramework.Oid4Vc.Database.Migration.Abstraction; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models; -using WalletFramework.Oid4Vc.Oid4Vp.Models; -using WalletFramework.Oid4Vc.Oid4Vp.Services; -using WalletFramework.SdJwtVc.Models; -using WalletFramework.SdJwtVc.Models.Records; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; - -namespace WalletFramework.Oid4Vc.Database.Migration.Implementations; - -internal class MigrationStepsProvider( - IAgentProvider agentProvider, - ICredentialSetStorage credentialSetStorage, - IMdocStorage mdocStorage, - IWalletRecordService walletRecordService, - IOid4VpRecordService oid4VpRecordService, - ISdJwtVcHolderService sdJwtVcHolderService) : IMigrationStepsProvider -{ - public IEnumerable Get() - { - var sdJwtStep = new MigrationStep( - 1, - 2, - typeof(SdJwtRecord), - async records => - { - var sdJwtRecords = records.OfType().ToList(); - foreach (var record in sdJwtRecords) - { - if (string.IsNullOrWhiteSpace(record.CredentialSetId)) - { - var credentialSetRecord = new CredentialSetRecord(); - credentialSetRecord.AddSdJwtData(record); - await credentialSetStorage.Add(credentialSetRecord); - record.CredentialSetId = credentialSetRecord.CredentialSetId; - } - - var context = await agentProvider.GetContextAsync(); - await sdJwtVcHolderService.UpdateAsync(context, record); - } - - return sdJwtRecords; - }, - async () => - { - var query = SearchQuery.Less( - nameof(MdocRecord.RecordVersion), - "2"); - - var context = await agentProvider.GetContextAsync(); - var records = await sdJwtVcHolderService.ListAsync(context, query); - return records.Any() - ? records.Cast().ToList() - : Option>.None; - }); - - var mdocStep = new MigrationStep( - 1, - 2, - typeof(MdocRecord), - async records => - { - var mdocRecords = records.OfType().ToList(); - foreach (var record in mdocRecords) - { - if (string.IsNullOrWhiteSpace(record.CredentialSetId)) - { - var credentialSetRecord = new CredentialSetRecord(); - credentialSetRecord.AddMdocData(record); - await credentialSetStorage.Add(credentialSetRecord); - record.CredentialSetId = credentialSetRecord.CredentialSetId; - } - - await mdocStorage.Update(record); - } - - return mdocRecords; - }, - async () => - { - var query = SearchQuery.Not(SearchQuery.Greater(nameof(MdocRecord.RecordVersion), "1")); - var someQuery = Option.Some(query); - - var mdocs = await mdocStorage.List(someQuery); - return - from mdocRecords in mdocs - select mdocRecords.Cast(); - }); - - var presentationRecordStep = new MigrationStep( - 1, - 2, - typeof(OidPresentationRecord), - async records => - { - var result = new List(); - - var context = await agentProvider.GetContextAsync(); - - var presentationRecords = records.OfType(); - foreach (var presentationRecord in presentationRecords) - { - var presentedCredentialSets = new List(); - - foreach (var presentedCredential in presentationRecord.PresentedCredentials) - { - var record = Option>.None; - - var sdJwtRecord = await walletRecordService.GetAsync(context.Wallet, presentedCredential.CredentialId); - if (sdJwtRecord != null) - { - record = Option>.Some(sdJwtRecord); - } - else - { - var mDocRecord = await walletRecordService.GetAsync(context.Wallet, presentedCredential.CredentialId); - if (mDocRecord != null) - { - record = Option>.Some(mDocRecord); - } - } - - if (record.IsNone) - continue; - - var presentedRecord = record.Value(); - presentedRecord.Match( - sdJwt => - { - presentedCredentialSets.Add( - new PresentedCredentialSet - { - CredentialSetId = CredentialSetId.ValidCredentialSetId(sdJwt.CredentialSetId) - .UnwrapOrThrow(), - SdJwtCredentialType = Vct.ValidVct(sdJwt.Vct).UnwrapOrThrow(), - PresentedClaims = presentedCredential.PresentedClaims - }); - - return Unit.Default; - }, - mDoc => - { - presentedCredentialSets.Add( - new PresentedCredentialSet - { - CredentialSetId = CredentialSetId.ValidCredentialSetId(mDoc.CredentialSetId) - .UnwrapOrThrow(), - MDocCredentialType = mDoc.DocType, - PresentedClaims = presentedCredential.PresentedClaims - }); - - return Unit.Default; - }); - } - - var oidPresentationRecord = new OidPresentationRecord - { - Id = Guid.NewGuid().ToString(), - ClientId = presentationRecord.ClientId, - ClientMetadata = presentationRecord.ClientMetadata, - Name = presentationRecord.Name, - PresentedCredentialSets = presentedCredentialSets - }; - - await oid4VpRecordService.StoreAsync(context,oidPresentationRecord); - - await walletRecordService.DeleteAsync(context.Wallet, - presentationRecord.Id); - - result.Add(oidPresentationRecord); - } - - return result; - }, - async () => - { - var query = SearchQuery.Less(nameof(OidPresentationRecord.RecordVersion), "2"); - - var context = await agentProvider.GetContextAsync(); - return await walletRecordService.SearchAsync(context.Wallet, query, null, 100); - }); - - var addCredentialFormatToSdJwtStep = new MigrationStep( - 2, - 3, - typeof(SdJwtRecord), - async records => - { - var sdJwtRecords = records.OfType().ToList(); - foreach (var record in sdJwtRecords) - { - if (string.IsNullOrWhiteSpace(record.Format)) - { - record.Format = FormatFun.CreateSdJwtVcFormat(); - } - - var context = await agentProvider.GetContextAsync(); - await sdJwtVcHolderService.UpdateAsync(context, record); - } - - return sdJwtRecords; - }, - async () => - { - var query = SearchQuery.Equal("~" + nameof(SdJwtRecord.RecordVersion), "2"); - - var context = await agentProvider.GetContextAsync(); - var records = await sdJwtVcHolderService.ListAsync(context, query); - return records.Any() - ? records.Cast().ToList() - : Option>.None; - }); - - return [sdJwtStep, mdocStep, presentationRecordStep, addCredentialFormatToSdJwtStep]; - } -} diff --git a/src/WalletFramework.Oid4Vc/Database/Migration/Implementations/RecordsMigrationService.cs b/src/WalletFramework.Oid4Vc/Database/Migration/Implementations/RecordsMigrationService.cs deleted file mode 100644 index 3aac0f9b..00000000 --- a/src/WalletFramework.Oid4Vc/Database/Migration/Implementations/RecordsMigrationService.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; -using WalletFramework.Oid4Vc.Database.Migration.Abstraction; - -namespace WalletFramework.Oid4Vc.Database.Migration.Implementations; - -public class RecordsMigrationService : IRecordsMigrationService -{ - private readonly IAgentProvider _agentProvider; - private readonly IWalletRecordService _walletRecordService; - - public RecordsMigrationService( - IMigrationStepsProvider migrationStepsProvider, - IAgentProvider agentProvider, - IWalletRecordService walletRecordService) - { - _agentProvider = agentProvider; - _walletRecordService = walletRecordService; - - var steps = migrationStepsProvider.Get(); - _walletFrameworkMigrationSteps.AddRange(steps); - } - - private readonly List _migrationSteps = []; - private readonly List _walletFrameworkMigrationSteps = []; - - public List MigrationSteps => - _walletFrameworkMigrationSteps - .Append(_migrationSteps) - .ToList(); - - public async Task Migrate() - { - var stepGroups = MigrationSteps.GroupBy(step => new { step.RecordType, step.OldVersion, step.NewVersion }).OrderBy(x => x.Key.OldVersion).ThenBy(x => x.Key.NewVersion); - foreach (var stepGroup in stepGroups) - { - var migratedRecords = new List(); - - foreach (var step in stepGroup) - { - var stepPendingRecords = await step.GetPendingRecords(); - await stepPendingRecords.IfSomeAsync(async pendingRecords => - { - var records = pendingRecords.ToList(); - migratedRecords.AddRange(await step.Execute(records)); - }); - } - - var context = await _agentProvider.GetContextAsync(); - foreach (var record in migratedRecords) - { - record.RecordVersion = stepGroup.Key.NewVersion; - await _walletRecordService.UpdateAsync(context.Wallet, record); - } - } - } - - public IEnumerable AddMigrationStep(MigrationStep migrationStep) - { - _migrationSteps.Add(migrationStep); - return MigrationSteps; - } - - public IEnumerable AddMigrationSteps(IEnumerable steps) - { - _migrationSteps.AddRange(steps); - return MigrationSteps; - } - - public IEnumerable GetMigrationSteps() => MigrationSteps; -} diff --git a/src/WalletFramework.Oid4Vc/Database/Migration/MigrationStep.cs b/src/WalletFramework.Oid4Vc/Database/Migration/MigrationStep.cs deleted file mode 100644 index 1584ef57..00000000 --- a/src/WalletFramework.Oid4Vc/Database/Migration/MigrationStep.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Hyperledger.Aries.Storage; -using LanguageExt; - -namespace WalletFramework.Oid4Vc.Database.Migration; - -public record MigrationStep( - int OldVersion, - int NewVersion, - Type RecordType, - Func, Task>> Execute, - Func>>> GetPendingRecords); diff --git a/src/WalletFramework.Oid4Vc/DependencyInjection/ServiceCollectionExtensions.cs b/src/WalletFramework.Oid4Vc/DependencyInjection/ServiceCollectionExtensions.cs index 5f98bf2e..551e6b91 100644 --- a/src/WalletFramework.Oid4Vc/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/WalletFramework.Oid4Vc/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,16 +1,20 @@ using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Events; using WalletFramework.Core.StatusList; using WalletFramework.MdocLib.Device.Abstractions; using WalletFramework.MdocLib.Device.Implementations; using WalletFramework.MdocLib.Security.Cose.Abstractions; using WalletFramework.MdocLib.Security.Cose.Implementations; +using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; using WalletFramework.Oid4Vc.ClientAttestation; using WalletFramework.Oid4Vc.CredentialSet; -using WalletFramework.Oid4Vc.Database.Migration.Abstraction; -using WalletFramework.Oid4Vc.Database.Migration.Implementations; +using WalletFramework.Oid4Vc.CredentialSet.Models; +using WalletFramework.Oid4Vc.CredentialSet.Persistence; using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Implementations; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; using WalletFramework.Oid4Vc.Oid4Vci.Authorization.Abstractions; using WalletFramework.Oid4Vc.Oid4Vci.Authorization.DPop.Abstractions; using WalletFramework.Oid4Vc.Oid4Vci.Authorization.DPop.Implementations; @@ -24,15 +28,20 @@ using WalletFramework.Oid4Vc.Oid4Vci.Implementations; using WalletFramework.Oid4Vc.Oid4Vci.Issuer.Abstractions; using WalletFramework.Oid4Vc.Oid4Vci.Issuer.Implementations; +using WalletFramework.Oid4Vc.Oid4Vp; using WalletFramework.Oid4Vc.Oid4Vp.AuthResponse.Encryption.Abstractions; using WalletFramework.Oid4Vc.Oid4Vp.AuthResponse.Encryption.Implementations; using WalletFramework.Oid4Vc.Oid4Vp.Dcql.Services; +using WalletFramework.Oid4Vc.Oid4Vp.Persistence; using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Services; using WalletFramework.Oid4Vc.Oid4Vp.Services; using WalletFramework.Oid4Vc.RelyingPartyAuthentication.Abstractions; using WalletFramework.Oid4Vc.RelyingPartyAuthentication.Implementations; using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Persistence; using WalletFramework.SdJwtVc.Services; +using WalletFramework.Storage; +using WalletFramework.Storage.Records; namespace WalletFramework.Oid4Vc.DependencyInjection; @@ -45,10 +54,8 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddOpenIdServices(this IServiceCollection builder) { builder.AddSingleton(); - builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); - builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); @@ -56,27 +63,30 @@ public static IServiceCollection AddOpenIdServices(this IServiceCollection build builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); - builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); + builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); - builder.AddSingleton(); - builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); - builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); - builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); builder.AddSingleton(); + builder.AddSingleton(); + + builder.AddScoped, MdocCredentialRepository>(); + builder.AddScoped, SdJwtCredentialRepository>(); + builder.AddScoped, CredentialDataSetRepository>(); + builder.AddScoped, CompletedPresentationRepository>(); + builder.AddScoped, AuthFlowSessionRepository>(); builder.AddSdJwtVcServices(); @@ -95,22 +105,50 @@ public static IServiceCollection AddExtendedOid4VciClientService(); - builder.AddSingleton(x => x.GetService()); - builder.AddSingleton(x => x.GetService()); + builder.AddSingleton(x => x.GetService()!); + builder.AddSingleton(x => x.GetService()!); return builder; } - /// - /// Adds the extended CredentialSet service. - /// - /// The extended CredentialSet credential service. - /// Builder. - /// The 2nd type parameter. + // /// + // /// Adds the extended CredentialSet service. + // /// + // /// The extended CredentialSet credential service. + // /// Builder. + // /// The 2nd type parameter. public static IServiceCollection AddExtendedCredentialSetStorage(this IServiceCollection builder) - where TImplementation : class, ICredentialSetStorage + where TImplementation : class, IDomainRepository { builder.AddSingleton(); - builder.AddSingleton(x => x.GetService()); + builder.AddSingleton>( + x => x.GetService()!); + return builder; + } + + /// + /// Configures wallet storage for OpenID features. Registers the framework's record configurations and allows + /// the consumer to add additional records. + /// + /// Service collection. + /// SQLite connection string. + /// Optional callback to append additional record registrations. + /// The service collection for chaining. + public static IServiceCollection ConfigureStorage( + this IServiceCollection builder, + string connectionString, + Action? configure = null) + { + Storage.Database.DependencyInjection.ServiceCollectionExtensions.ConfigureStorage(builder, connectionString, recordsBuilder => + { + recordsBuilder.AddRecord(); + recordsBuilder.AddRecord(); + recordsBuilder.AddRecord(); + recordsBuilder.AddRecord(); + recordsBuilder.AddRecord(); + + configure?.Invoke(recordsBuilder); + }); + return builder; } } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IMdocCandidateService.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IMdocCandidateService.cs index c2dc0237..231f8044 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IMdocCandidateService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IMdocCandidateService.cs @@ -6,5 +6,5 @@ namespace WalletFramework.Oid4Vc.Oid4Vci.Abstractions; public interface IMdocCandidateService { - Task>> GetCandidates(DeviceRequest deviceRequest); + Task>> GetCandidates(DeviceRequest deviceRequest); } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IMdocStorage.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IMdocStorage.cs deleted file mode 100644 index 17648f91..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IMdocStorage.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Hyperledger.Aries.Storage; -using LanguageExt; -using WalletFramework.Core.Credentials; -using WalletFramework.MdocVc; - -namespace WalletFramework.Oid4Vc.Oid4Vci.Abstractions; - -public interface IMdocStorage -{ - public Task Add(MdocRecord record); - - public Task> Get(CredentialId credentialId); - - public Task>> List( - Option query, - int count = 100, - int skip = 0); - - public Task>> List(CredentialSetId id); - - public Task>> ListAll() => List(Option.None); - - public Task Update(MdocRecord record); - - public Task Delete(MdocRecord record); -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IOid4VciClientService.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IOid4VciClientService.cs index 5b13464e..0c712ea4 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IOid4VciClientService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IOid4VciClientService.cs @@ -55,7 +55,7 @@ Task InitiateAuthFlow( /// /// A list of credentials. /// - Task>> RequestCredentialSet( + Task>> RequestCredentialSet( IssuanceSession issuanceSession, Option clientAttestationDetails); @@ -89,7 +89,7 @@ Task> ProcessOffer( /// Credential offer and Issuer Metadata /// The client attestation details /// The Transaction Code. - Task>> AcceptOffer( + Task>> AcceptOffer( CredentialOfferMetadata credentialOfferMetadata, Option clientAttestationDetails, string? transactionCode); diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Abstractions/IAuthFlowSessionStorage.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Abstractions/IAuthFlowSessionStorage.cs deleted file mode 100644 index be79f0db..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Abstractions/IAuthFlowSessionStorage.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Hyperledger.Aries.Agents; -using LanguageExt; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Records; - -namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Abstractions; - -/// -/// Service for managing authorization records. They are used during the VCI Authorization Code Flow to hold session -/// relevant inforation. -/// -public interface IAuthFlowSessionStorage -{ - /// - /// Deletes the authorization session record by the session identifier. - /// - /// Agent Context - /// Session State Identifier of a Authorization Code Flow session - /// - Task DeleteAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState); - - /// - /// Retrieves the authorization session record by the session identifier. - /// - /// Agent Context - /// Session State Identifier of a Authorization Code Flow session - /// - Task GetAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState); - - /// - /// Updates the authorization session record by the session identifier. - /// - /// Agent Context - /// the updated Authorization Session Record - /// - Task UpdateAsync(IAgentContext context, AuthFlowSessionRecord record); - - /// - /// Stores the authorization session record. - /// - /// The Agent Context - /// Options specified by the Client (Wallet) - /// - /// Parameters required for the authorization during the VCI authorization code - /// flow. - /// - /// Session State Identifier of a Authorization Code Flow session - /// Session State Identifier of a Authorization Code Flow session - /// - Task StoreAsync( - IAgentContext agentContext, - AuthorizationData authorizationData, - AuthorizationCodeParameters authorizationCodeParameters, - AuthFlowSessionState authFlowSessionState, - Option specVersion); -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/AuthFlowSession.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/AuthFlowSession.cs new file mode 100644 index 00000000..9886a00c --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/AuthFlowSession.cs @@ -0,0 +1,63 @@ +using LanguageExt; +using static LanguageExt.Prelude; +using WalletFramework.Core.Functional; +using Newtonsoft.Json.Linq; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; + +namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow; + +public sealed record AuthFlowSession( + AuthFlowSessionState AuthFlowSessionState, + AuthorizationData AuthorizationData, + AuthorizationCodeParameters AuthorizationCodeParameters, + Option SpecVersion) +{ + public static AuthFlowSession Create( + AuthorizationData authorizationData, + string codeChallenge, + string codeVerifier, + AuthFlowSessionState authFlowSessionState, + Option specVersion) + { + var codeParameters = new AuthorizationCodeParameters(codeChallenge, codeVerifier); + return new AuthFlowSession(authFlowSessionState, authorizationData, codeParameters, specVersion); + } +} + +public static class AuthFlowSessionJson +{ + private const string SessionStateJsonKey = "auth_flow_session_state"; + private const string AuthorizationDataJsonKey = "authorization_data"; + private const string AuthorizationCodeParametersJsonKey = "authorization_code_parameters"; + private const string SpecVersionJsonKey = "spec_version"; + + public static JObject EncodeToJson(this AuthFlowSession session) + { + var result = new JObject + { + { SessionStateJsonKey, session.AuthFlowSessionState.AsString() }, + { AuthorizationDataJsonKey, session.AuthorizationData.EncodeToJson() }, + { AuthorizationCodeParametersJsonKey, JObject.FromObject(session.AuthorizationCodeParameters) } + }; + + session.SpecVersion.IfSome(version => result.Add(SpecVersionJsonKey, version)); + + return result; + } + + public static AuthFlowSession DecodeFromJson(JObject json) + { + var stateStr = json[SessionStateJsonKey]!.ToString(); + var state = AuthFlowSessionState.ValidAuthFlowSessionState(stateStr).UnwrapOrThrow(); + + var authorizationData = AuthorizationDataFun.DecodeFromJson(json[AuthorizationDataJsonKey]!.ToObject()!); + var codeParams = json[AuthorizationCodeParametersJsonKey]!.ToObject()!; + var specVersion = json[SpecVersionJsonKey]?.ToObject(); + + var specOpt = specVersion.HasValue + ? Some(specVersion.Value) + : Option.None; + + return new AuthFlowSession(state, authorizationData, codeParams, specOpt); + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Implementations/AuthFlowSessionStorage.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Implementations/AuthFlowSessionStorage.cs deleted file mode 100644 index 2317bfff..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Implementations/AuthFlowSessionStorage.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; -using LanguageExt; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Records; -using WalletFramework.Oid4Vc.Oid4Vp.Services; - -namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Implementations; - -/// -public class AuthFlowSessionStorage : IAuthFlowSessionStorage -{ - /// - /// Initializes a new instance of the class. - /// - /// The service responsible for wallet record operations. - public AuthFlowSessionStorage(IWalletRecordService recordService) - { - _recordService = recordService; - } - - private readonly IWalletRecordService _recordService; - - /// - public async Task StoreAsync(IAgentContext agentContext, - AuthorizationData authorizationData, - AuthorizationCodeParameters authorizationCodeParameters, - AuthFlowSessionState authFlowSessionState, - Option specVersion) - { - var record = new AuthFlowSessionRecord( - authorizationData, - authorizationCodeParameters, - authFlowSessionState, - specVersion.ToNullable()); - - await _recordService.AddAsync(agentContext.Wallet, record); - - return record.Id; - } - - /// - public async Task GetAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState) - { - var record = await _recordService.GetAsync(context.Wallet, authFlowSessionState); - return record!; - } - - /// - public async Task DeleteAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState) => - await _recordService.DeleteAsync(context.Wallet, authFlowSessionState); - - /// - public async Task UpdateAsync(IAgentContext context, AuthFlowSessionRecord record) => - await _recordService.UpdateAsync(context.Wallet, record); -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthFlowSessionState.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthFlowSessionState.cs index d66f1b8c..f841379c 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthFlowSessionState.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthFlowSessionState.cs @@ -22,6 +22,8 @@ public struct AuthFlowSessionState /// /// public static implicit operator string(AuthFlowSessionState authFlowSessionState) => authFlowSessionState.Value; + + public string AsString() => Value; public static Validation ValidAuthFlowSessionState(string authFlowSessionState) { diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthorizationCodeParameters.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthorizationCodeParameters.cs index 5cc1a381..d04f0a82 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthorizationCodeParameters.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthorizationCodeParameters.cs @@ -25,7 +25,7 @@ public record AuthorizationCodeParameters public string Verifier { get; } [JsonConstructor] - internal AuthorizationCodeParameters(string challenge, string verifier) + public AuthorizationCodeParameters(string challenge, string verifier) { if (string.IsNullOrWhiteSpace(challenge) || string.IsNullOrWhiteSpace(verifier)) { diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRecord.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRecord.cs new file mode 100644 index 00000000..f4fcbdb7 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRecord.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json.Linq; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; + +/// +/// Storage-only record for VCI AuthFlow sessions. +/// +public sealed record AuthFlowSessionRecord : RecordBase +{ + public string SessionState { get; init; } + + public string Serialized { get; init; } + +#pragma warning disable CS8618 + // Used by EF + // ReSharper disable once UnusedMember.Local + private AuthFlowSessionRecord() : base(Guid.NewGuid()) + { + } +#pragma warning restore CS8618 + + public AuthFlowSessionRecord(AuthFlowSession domain) : base(Guid.NewGuid()) + { + SessionState = domain.AuthFlowSessionState.AsString(); + Serialized = domain.EncodeToJson().ToString(); + } + + public AuthFlowSession ToDomainModel() + { + return AuthFlowSessionJson.DecodeFromJson(JObject.Parse(Serialized)); + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRecordConfiguration.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRecordConfiguration.cs new file mode 100644 index 00000000..a8fb60e4 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRecordConfiguration.cs @@ -0,0 +1,17 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; + +public sealed record AuthFlowSessionRecordConfiguration : IRecordConfiguration +{ + public Unit Configure(ModelBuilder modelBuilder) + { + var entity = modelBuilder.Entity(); + entity.HasIndex(r => r.SessionState).IsUnique(); + entity.Property(r => r.SessionState).IsRequired(); + entity.Property(r => r.Serialized).IsRequired(); + return Unit.Default; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRepository.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRepository.cs new file mode 100644 index 00000000..1564d93c --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Persistence/AuthFlowSessionRepository.cs @@ -0,0 +1,107 @@ +using LanguageExt; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; +using WalletFramework.Storage; +using WalletFramework.Storage.Repositories; + +namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; + +public class AuthFlowSessionRepository(IRepository repository) + : IDomainRepository +{ + public async Task Add(AuthFlowSession domainModel) + { + var sessionState = domainModel.AuthFlowSessionState.AsString(); + + var existingOpt = await repository.Find(r => r.SessionState == sessionState); + await existingOpt.Match( + Some: async list => + { + var existing = list.First(); + var updated = existing with { Serialized = domainModel.EncodeToJson().ToString() }; + await repository.Update(updated); + }, + None: async () => + { + await repository.Add(new AuthFlowSessionRecord(domainModel)); + }); + + return Unit.Default; + } + + public async Task AddMany(IEnumerable domainModels) + { + var records = domainModels.Select(d => new AuthFlowSessionRecord(d)); + await repository.AddMany(records); + return Unit.Default; + } + + public async Task Delete(AuthFlowSessionState id) + { + var idStr = id.AsString(); + var recs = await repository.Find(r => r.SessionState == idStr); + await recs.Match( + Some: async list => + { + foreach (var r in list) + await repository.Remove(r); + }, + None: () => Task.CompletedTask); + return Unit.Default; + } + + public async Task Delete(AuthFlowSession domainModel) + { + var idStr = domainModel.AuthFlowSessionState.AsString(); + var recs = await repository.Find(r => r.SessionState == idStr); + await recs.Match( + Some: async list => + { + foreach (var r in list) + await repository.Remove(r); + }, + None: () => Task.CompletedTask); + return Unit.Default; + } + + public async Task>> Find(ISearchConfig config) + { + var records = await repository.Find(config.ToPredicate()); + return from recs in records + let domains = recs.Select(r => r.ToDomainModel()) + select domains.ToList(); + } + + public async Task> GetById(AuthFlowSessionState id) + { + var idStr = id.AsString(); + var records = await repository.Find(r => r.SessionState == idStr); + return from recs in records + let record = recs.FirstOrDefault() + select record?.ToDomainModel(); + } + + public async Task>> ListAll() + { + var records = await repository.ListAll(); + return from recs in records + let domains = recs.Select(r => r.ToDomainModel()) + select domains.ToList(); + } + + public async Task Update(AuthFlowSession domainModel) + { + var idStr = domainModel.AuthFlowSessionState.AsString(); + var existingOpt = await repository.Find(r => r.SessionState == idStr); + + await existingOpt.Match( + Some: async list => + { + var existing = list.First(); + var updated = existing with { Serialized = domainModel.EncodeToJson().ToString() }; + await repository.Update(updated); + }, + None: async () => { await repository.Add(new AuthFlowSessionRecord(domainModel)); }); + + return Unit.Default; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Records/AuthFlowSessionRecord.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Records/AuthFlowSessionRecord.cs deleted file mode 100644 index 576fffc2..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Records/AuthFlowSessionRecord.cs +++ /dev/null @@ -1,139 +0,0 @@ -using Hyperledger.Aries.Storage; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using WalletFramework.Core.Functional; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; - -namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Records; - -/// -/// Represents the authorization session record. Used during the VCI Authorization Code Flow to hold session relevant information. -/// -[JsonConverter(typeof(AuthFlowSessionRecordConverter))] -public sealed class AuthFlowSessionRecord : RecordBase -{ - /// - /// The session specific state id. - /// - [JsonIgnore] - public AuthFlowSessionState AuthFlowSessionState - { - get => AuthFlowSessionState - .ValidAuthFlowSessionState(Id) - .UnwrapOrThrow(new InvalidOperationException("AuthFlowSessionState is corrupt")); - set - { - string str = value; - Id = str; - } - } - - /// - /// The authorization data. - /// - public AuthorizationData AuthorizationData { get; set; } - - /// - /// The parameters for the 'authorization_code' grant type. - /// - public AuthorizationCodeParameters AuthorizationCodeParameters { get; } - - /// - /// Used to track the VCI Specification verison - /// - public int? SpecVersion { get; } - - /// - /// Initializes a new instance of the class. - /// - public override string TypeName => "AF.VciAuthorizationSessionRecord"; - -#pragma warning disable CS8618 - /// - /// Initializes a new instance of the class. - /// - public AuthFlowSessionRecord() - { - } -#pragma warning restore CS8618 - - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - public AuthFlowSessionRecord( - AuthorizationData authorizationData, - AuthorizationCodeParameters authorizationCodeParameters, - AuthFlowSessionState authFlowSessionState, - int? specVersion) - { - AuthFlowSessionState = authFlowSessionState; - RecordVersion = 1; - AuthorizationCodeParameters = authorizationCodeParameters; - AuthorizationData = authorizationData; - SpecVersion = specVersion; - } -} - -public class AuthFlowSessionRecordConverter : JsonConverter -{ - public override void WriteJson(JsonWriter writer, AuthFlowSessionRecord? value, JsonSerializer serializer) - { - var json = value!.EncodeToJson(); - json.WriteTo(writer); - } - - public override AuthFlowSessionRecord ReadJson( - JsonReader reader, - Type objectType, - AuthFlowSessionRecord? existingValue, - bool hasExistingValue, - JsonSerializer serializer) - { - var json = JObject.Load(reader); - return AuthFlowSessionRecordFun.DecodeFromJson(json); - } -} - -public static class AuthFlowSessionRecordFun -{ - private const string AuthorizationDataJsonKey = "authorization_data"; - private const string AuthorizationCodeParametersJsonKey = "authorization_code_parameters"; - private const string SpecVersionJsonKey = "spec_version"; - - public static JObject EncodeToJson(this AuthFlowSessionRecord record) - { - var authorizationData = record.AuthorizationData.EncodeToJson(); - var authorizationCodeParameters = JObject.FromObject(record.AuthorizationCodeParameters); - - return new JObject - { - { nameof(RecordBase.Id), record.Id }, - { AuthorizationDataJsonKey, authorizationData }, - { AuthorizationCodeParametersJsonKey, authorizationCodeParameters }, - { SpecVersionJsonKey, record.SpecVersion } - }; - } - - public static AuthFlowSessionRecord DecodeFromJson(JObject json) - { - var idJson = json[nameof(RecordBase.Id)]!.ToObject()!; - var id = AuthFlowSessionStateFun.DecodeFromJson(idJson); - - var authCodeParameters = JsonConvert.DeserializeObject( - json[AuthorizationCodeParametersJsonKey]!.ToString() - ); - - var authorizationData = AuthorizationDataFun - .DecodeFromJson(json[AuthorizationDataJsonKey]!.ToObject()!); - - var specVersion = json[SpecVersionJsonKey]!.ToObject(); - - var result = new AuthFlowSessionRecord(authorizationData, authCodeParameters!, id, specVersion); - - return result; - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/ClaimDisplay.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/ClaimDisplay.cs new file mode 100644 index 00000000..cdb7d598 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/ClaimDisplay.cs @@ -0,0 +1,57 @@ +using LanguageExt; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Functional; +using WalletFramework.Core.Json; +using WalletFramework.Core.Localization; +using static WalletFramework.Core.Localization.Locale; +using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.ClaimDisplayJsonExtensions; + +namespace WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models; + +public record ClaimDisplay +{ + public Option Name { get; } + + public Option Locale { get; } + + private ClaimDisplay(Option name, Option locale) + { + Name = name; + Locale = locale; + } + + private static ClaimDisplay Create(Option name, Option locale) => + new(name, locale); + + public static Validation ValidClaimDisplay(JToken config) + { + var name = + from jToken in config.GetByKey(NameJsonKey) + select jToken.ToObject(); + + var locale = + from jToken in config.GetByKey(LocaleJsonKey) + from validLocale in ValidLocale(jToken) + select validLocale; + + return ValidationFun.Valid(Create) + .Apply(name.ToOption()) + .Apply(locale.ToOption()); + } +} + +public static class ClaimDisplayJsonExtensions +{ + public const string NameJsonKey = "name"; + public const string LocaleJsonKey = "locale"; + + public static JObject EncodeToJson(this ClaimDisplay display) + { + var result = new JObject(); + + display.Locale.IfSome(locale => result.Add(LocaleJsonKey, locale.ToString())); + display.Name.IfSome(name => result.Add(NameJsonKey, name)); + + return result; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/ClaimMetadata.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/ClaimMetadata.cs new file mode 100644 index 00000000..2262056b --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/ClaimMetadata.cs @@ -0,0 +1,80 @@ +using LanguageExt; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.ClaimPaths; +using WalletFramework.Core.Functional; +using WalletFramework.Core.Json; +using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.ClaimMetadataJsonExtensions; + +namespace WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models; + +public record ClaimMetadata +{ + public ClaimPath Path { get; } + + public Option> Display { get; } + + public Option Mandatory { get; } + + private ClaimMetadata(ClaimPath claimPath, Option> claimDisplays, Option mandatory) + { + Path = claimPath; + Display = claimDisplays; + Mandatory = mandatory; + } + + private static ClaimMetadata Create(ClaimPath claimPath, Option> claimDisplays, Option mandatory) => + new(claimPath, claimDisplays, mandatory); + + public static Validation ValidClaimMetadata(JToken config, Func> claimPathValidation) + { + var claimPath = + from jToken in config.GetByKey(PathJsonKey) + from jArray in claimPathValidation(jToken) + select jArray; + + var claimDisplays = + from jToken in config.GetByKey(DisplayJsonKey) + from jArray in jToken.ToJArray() + from claimDisplay in jArray.TraverseAny(ClaimDisplay.ValidClaimDisplay) + select claimDisplay.ToList(); + + var mandatory = + from jToken in config.GetByKey(MandatoryJsonKey) + select jToken.ToObject(); + + var result = ValidationFun.Valid(Create) + .Apply(claimPath) + .Apply(claimDisplays.ToOption()) + .Apply(mandatory.ToOption()); + + return result; + } +} + +public static class ClaimMetadataJsonExtensions +{ + public const string PathJsonKey = "path"; + public const string DisplayJsonKey = "display"; + public const string MandatoryJsonKey = "mandatory"; + + public static JObject EncodeToJson(this ClaimMetadata display) + { + var result = new JObject(); + + result.Add(PathJsonKey, ClaimPath.ToJArray(display.Path)); + + display.Display.IfSome(claimDisplays => + { + var claimsArray = new JArray(); + foreach (var claimDisplay in claimDisplays) + { + claimsArray.Add(claimDisplay.EncodeToJson()); + } + result.Add(DisplayJsonKey, claimsArray); + }); + + display.Mandatory.IfSome(mandatory => { result.Add(MandatoryJsonKey, mandatory); }); + + return result; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/CredentialConfiguration.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/CredentialConfiguration.cs index 823873bd..fe84c495 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/CredentialConfiguration.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/CredentialConfiguration.cs @@ -1,5 +1,6 @@ using LanguageExt; using Newtonsoft.Json.Linq; +using WalletFramework.Core.ClaimPaths; using WalletFramework.Core.Functional; using WalletFramework.Core.Json; using static WalletFramework.Core.Functional.ValidationFun; @@ -9,8 +10,8 @@ using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.CryptograhicSigningAlgValue; using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.ProofTypeId; using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.ProofTypeMetadata; -using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.CredentialDisplay; using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.CredentialConfigurationFun; +using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.CredentialMetadata; namespace WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models; @@ -49,7 +50,7 @@ public record CredentialConfiguration /// /// Gets a list of display properties of the supported credential for different languages. /// - public Option> Display { get; } + public Option CredentialMetadata { get; } private CredentialConfiguration( Format format, @@ -57,14 +58,14 @@ private CredentialConfiguration( Option> cryptographicBindingMethodsSupported, Option> credentialSigningAlgValuesSupported, Option> proofTypesSupported, - Option> display) + Option credentialMetadata) { Format = format; Scope = scope; CryptographicBindingMethodsSupported = cryptographicBindingMethodsSupported; CredentialSigningAlgValuesSupported = credentialSigningAlgValuesSupported; ProofTypesSupported = proofTypesSupported; - Display = display; + CredentialMetadata = credentialMetadata; } private static CredentialConfiguration Create( @@ -73,15 +74,15 @@ private static CredentialConfiguration Create( Option> cryptographicBindingMethodsSupported, Option> credentialSigningAlgValuesSupported, Option> proofTypesSupported, - Option> display) => new( + Option credentialMetadata) => new( format, scope, cryptographicBindingMethodsSupported, credentialSigningAlgValuesSupported, proofTypesSupported, - display); + credentialMetadata); - public static Validation ValidCredentialConfiguration(JToken credentialMetadata) + public static Validation ValidCredentialConfiguration(JToken credentialMetadata, Func> claimPathValidation) { var validBindingMethods = new Func>>(bindingMethods => from array in bindingMethods.ToJArray() @@ -96,11 +97,8 @@ from values in array.TraverseAny(ValidCryptograhicSigningAlgValue) var validProofTypes = new Func>>(proofTypes => proofTypes .ToJObject() .OnSuccess(jObject => jObject.ToValidDictionaryAny(ValidProofTypeId, ValidProofTypeMetadata))); - - var optionalCredentialDisplays = new Func>>(credentialDisplays => - from array in credentialDisplays.ToJArray().ToOption() - from displays in array.TraverseAny(OptionalCredentialDisplay) - select displays.ToList()); + + var optionalCredentialMetadata = new Func>(token => OptionalCredentialMetadata(token, claimPathValidation)); return Valid(Create) .Apply(credentialMetadata.GetByKey(FormatJsonKey).OnSuccess(ValidFormat)) @@ -108,7 +106,7 @@ from displays in array.TraverseAny(OptionalCredentialDisplay) .Apply(credentialMetadata.GetByKey(CryptographicBindingMethodsSupportedJsonKey).OnSuccess(validBindingMethods).ToOption()) .Apply(credentialMetadata.GetByKey(CredentialSigningAlgValuesSupportedJsonKey).OnSuccess(validSigningAlgValues).ToOption()) .Apply(credentialMetadata.GetByKey(ProofTypesSupportedJsonKey).OnSuccess(validProofTypes).ToOption()) - .Apply(credentialMetadata.GetByKey(DisplayJsonKey).ToOption().OnSome(optionalCredentialDisplays)); + .Apply(credentialMetadata.GetByKey(CredentialMetadataJsonKey).ToOption().OnSome(optionalCredentialMetadata)); } } @@ -119,7 +117,7 @@ public static class CredentialConfigurationFun public const string CryptographicBindingMethodsSupportedJsonKey = "cryptographic_binding_methods_supported"; public const string CredentialSigningAlgValuesSupportedJsonKey = "credential_signing_alg_values_supported"; public const string ProofTypesSupportedJsonKey = "proof_types_supported"; - public const string DisplayJsonKey = "display"; + public const string CredentialMetadataJsonKey = "credential_metadata"; public static JObject EncodeToJson(this CredentialConfiguration config) { @@ -159,14 +157,9 @@ public static JObject EncodeToJson(this CredentialConfiguration config) result.Add(ProofTypesSupportedJsonKey, proofTypes); }); - config.Display.IfSome(displays => + config.CredentialMetadata.IfSome(metadata => { - var displayArray = new JArray(); - foreach (var display in displays) - { - displayArray.Add(display.EncodeToJson()); - } - result.Add(DisplayJsonKey, displayArray); + result.Add(CredentialMetadataJsonKey, metadata.EncodeToJson()); }); return result; diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/CredentialMetadata.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/CredentialMetadata.cs new file mode 100644 index 00000000..f80738dc --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/CredentialMetadata.cs @@ -0,0 +1,91 @@ +using LanguageExt; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.ClaimPaths; +using WalletFramework.Core.Functional; +using WalletFramework.Core.Json; +using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.CredentialDisplay; +using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.CredentialMetadataFun; +using static WalletFramework.Core.Functional.ValidationFun; + +namespace WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models; + +/// +/// Represents credential metadata as defined in OpenID4VCI 1.0, containing display information and claims. +/// +public record CredentialMetadata +{ + /// + /// Gets a list of display properties of the supported credential for different languages. + /// + public Option> Display { get; } + + /// + /// Gets the claims token as provided by the issuer metadata. The concrete structure is format-specific. + /// + public Option> Claims { get; } + + private CredentialMetadata(Option> display, Option> claimMetadata) + { + Display = display; + Claims = claimMetadata; + } + + private static CredentialMetadata Create( + Option> display, + Option> claimMetadata) => new( + display, + claimMetadata); + + public static Option OptionalCredentialMetadata(JToken token, Func> claimPathValidation) => token + .ToJObject() + .ToOption() + .OnSome(jObject => + { + var optionalCredentialDisplays = new Func>>(credentialDisplays => + from array in credentialDisplays.ToJArray().ToOption() + from displays in array.TraverseAny(OptionalCredentialDisplay) + select displays.ToList()); + + var optionalClaimsMetadata = new Func>>(claimsMetadata => + from array in claimsMetadata.ToJArray().ToOption() + from claimMetadatas in array.TraverseAny(claimMetadata => ClaimMetadata.ValidClaimMetadata(claimMetadata, claimPathValidation).ToOption()) + select claimMetadatas.ToList()); + + return Valid(Create) + .Apply(jObject.GetByKey(DisplayJsonKey).ToOption().OnSome(optionalCredentialDisplays)) + .Apply(jObject.GetByKey(ClaimsJsonKey).ToOption().OnSome(optionalClaimsMetadata)).ToOption(); + }); +} + +public static class CredentialMetadataFun +{ + public const string DisplayJsonKey = "display"; + public const string ClaimsJsonKey = "claims"; + + public static JObject EncodeToJson(this CredentialMetadata metadata) + { + var result = new JObject(); + + metadata.Display.IfSome(displays => + { + var displayArray = new JArray(); + foreach (var display in displays) + { + displayArray.Add(display.EncodeToJson()); + } + result.Add(DisplayJsonKey, displayArray); + }); + + metadata.Claims.IfSome(claims => + { + var claimsArray = new JArray(); + foreach (var claim in claims) + { + claimsArray.Add(claim.EncodeToJson()); + } + result.Add(ClaimsJsonKey, claimsArray); + }); + + return result; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Format.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Format.cs index 1d809cb4..202a8fa0 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Format.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Format.cs @@ -26,7 +26,7 @@ public static Validation ValidFormat(JToken format) => format.ToJValue() ? new Format(str) : new FormatNotSupportedError(str).ToInvalid(); }); - + private static List SupportedFormats => [ Constants.SdJwtVcFormat, diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Mdoc/ClaimsMetadata.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Mdoc/ClaimsMetadata.cs deleted file mode 100644 index e0c31872..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Mdoc/ClaimsMetadata.cs +++ /dev/null @@ -1,85 +0,0 @@ -using LanguageExt; -using Newtonsoft.Json.Linq; -using WalletFramework.Core.Functional; -using WalletFramework.Core.Json; -using WalletFramework.MdocLib; -using WalletFramework.MdocLib.Elements; -using WalletFramework.MdocVc; -using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.Mdoc.ElementMetadata; - -namespace WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.Mdoc; - -public readonly struct ClaimsMetadata -{ - public Dictionary> Value { get; } - - private ClaimsMetadata(Dictionary> value) => - Value = value; - - public static Validation ValidClaimsMetadata(JObject claims) => claims - .ToValidDictionaryAll(NameSpace.ValidNameSpace, ValidElementMetadatas) - .OnSuccess(dictionary => new ClaimsMetadata(dictionary)); -} - -public static class ClaimsMetadataFun -{ - public static JObject EncodeToJson(this ClaimsMetadata metadata) - { - var result = new JObject(); - - foreach (var (key, elementMetadatas) in metadata.Value) - { - var elementsJson = new JObject(); - foreach (var (elementIdentifier, elementMetadata) in elementMetadatas) - { - elementsJson.Add(elementIdentifier, elementMetadata.EncodeToJson()); - } - - result.Add(key.ToString(), elementsJson); - } - - return result; - } - - public static Option>>> ToClaimsDisplays( - this ClaimsMetadata claimsMetadata) - { - var result = new Dictionary>>(); - - foreach (var nameSpacePair in claimsMetadata.Value) - { - var elementDisplays = new Dictionary>(); - foreach (var elementPair in nameSpacePair.Value) - { - elementPair.Value.Display.Match( - list => - { - var displays = list.Select(elementDisplay => - { - var name = - from elementName in elementDisplay.Name - from claimName in ClaimName.OptionClaimName(elementName) - select claimName; - - return new ClaimDisplay(name, elementDisplay.Locale); - }).ToList(); - elementDisplays.Add(elementPair.Key, displays); - }, - () => {} - ); - } - - if (elementDisplays.Any()) - result.Add(nameSpacePair.Key, elementDisplays); - } - - if (result.Any()) - { - return result; - } - else - { - return Option>>>.None; - } - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Mdoc/MdocConfiguration.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Mdoc/MdocConfiguration.cs index e71fd586..f6674be7 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Mdoc/MdocConfiguration.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/Mdoc/MdocConfiguration.cs @@ -1,5 +1,7 @@ using LanguageExt; using Newtonsoft.Json.Linq; +using WalletFramework.Core.ClaimPaths; +using WalletFramework.Core.ClaimPaths.Errors; using WalletFramework.Core.Functional; using WalletFramework.Core.Json; using WalletFramework.MdocLib; @@ -22,8 +24,6 @@ public record MdocConfiguration public Option> CryptographicSuitesSupported { get; } public Option> CryptographicCurvesSupported { get; } - - public Option Claims { get; } public Format Format => CredentialConfiguration.Format; @@ -32,15 +32,13 @@ private MdocConfiguration( DocType docType, Option policy, Option> cryptographicSuitesSupported, - Option> cryptographicCurvesSupported, - Option claims) + Option> cryptographicCurvesSupported) { CredentialConfiguration = credentialConfiguration; DocType = docType; Policy = policy; CryptographicSuitesSupported = cryptographicSuitesSupported; CryptographicCurvesSupported = cryptographicCurvesSupported; - Claims = claims; } private static MdocConfiguration Create( @@ -48,13 +46,28 @@ private static MdocConfiguration Create( DocType docType, Option policy, Option> cryptographicSuitesSupported, - Option> cryptographicCurvesSupported, - Option claims) => - new(credentialConfiguration, docType, policy, cryptographicSuitesSupported, cryptographicCurvesSupported, claims); + Option> cryptographicCurvesSupported) => + new(credentialConfiguration, docType, policy, cryptographicSuitesSupported, cryptographicCurvesSupported); public static Validation ValidMdocConfiguration(JObject config) { - var credentialConfiguration = CredentialConfiguration.ValidCredentialConfiguration(config); + var mDocClaimPathValidation = new Func>(token => + { + var mDocClaimPath = + from jArray in token.ToJArray() + from claimPath in ClaimPath.FromJArray(jArray) + let pathComponents = claimPath.GetPathComponents() + from _ in pathComponents.Count > 2 + && pathComponents[0].IsKey + && pathComponents[1].IsKey + ? ValidationFun.Valid(Unit.Default) + : new UnknownComponentError() + select claimPath; + + return mDocClaimPath; + }); + + var credentialConfiguration = CredentialConfiguration.ValidCredentialConfiguration(config, mDocClaimPathValidation); var docType = config.GetByKey(DocTypeJsonKey).OnSuccess(ValidDoctype); var policy = config.GetByKey(PolicyJsonKey).OnSuccess(ValidPolicy).ToOption(); @@ -73,19 +86,12 @@ public static Validation ValidMdocConfiguration(JObject confi .OnSuccess(curves => curves.ToList()) .ToOption(); - var claims = config - .GetByKey(ClaimsJsonKey) - .OnSuccess(token => token.ToJObject()) - .OnSuccess(ClaimsMetadata.ValidClaimsMetadata) - .ToOption(); - return ValidationFun.Valid(Create) .Apply(credentialConfiguration) .Apply(docType) .Apply(policy) .Apply(cryptographicSuitesSupported) - .Apply(cryptographicCurvesSupported) - .Apply(claims); + .Apply(cryptographicCurvesSupported); } } @@ -95,19 +101,18 @@ public static class MdocConfigurationFun public const string PolicyJsonKey = "policy"; public const string CryptographicSuitesSupportedJsonKey = "cryptographic_suites_supported"; public const string CryptographicCurvesSupportedJsonKey = "cryptographic_curves_supported"; - public const string ClaimsJsonKey = "claims"; - public static JObject EncodeToJson(this MdocConfiguration mdocConfig) + public static JObject EncodeToJson(this MdocConfiguration mDocConfig) { - var configJson = mdocConfig.CredentialConfiguration.EncodeToJson(); + var configJson = mDocConfig.CredentialConfiguration.EncodeToJson(); - configJson.Add(DocTypeJsonKey, mdocConfig.DocType.ToString()); + configJson.Add(DocTypeJsonKey, mDocConfig.DocType.ToString()); - mdocConfig.Policy.IfSome(policy => + mDocConfig.Policy.IfSome(policy => configJson.Add(PolicyJsonKey, policy.EncodeToJson()) ); - mdocConfig.CryptographicSuitesSupported.IfSome(suites => + mDocConfig.CryptographicSuitesSupported.IfSome(suites => { var suitesJson = new JArray(); foreach (var suite in suites) @@ -117,7 +122,7 @@ public static JObject EncodeToJson(this MdocConfiguration mdocConfig) configJson.Add(CryptographicSuitesSupportedJsonKey, suitesJson); }); - mdocConfig.CryptographicCurvesSupported.IfSome(curves => + mDocConfig.CryptographicCurvesSupported.IfSome(curves => { var curvesJson = new JArray(); foreach (var curve in curves) @@ -126,10 +131,6 @@ public static JObject EncodeToJson(this MdocConfiguration mdocConfig) } configJson.Add(CryptographicCurvesSupportedJsonKey, curvesJson); }); - - mdocConfig.Claims.IfSome(claims => - configJson.Add(ClaimsJsonKey, claims.EncodeToJson()) - ); return configJson; } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/SdJwt/SdJwtConfiguration.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/SdJwt/SdJwtConfiguration.cs index 919a1da4..6dd7d8bf 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/SdJwt/SdJwtConfiguration.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredConfiguration/Models/SdJwt/SdJwtConfiguration.cs @@ -1,10 +1,10 @@ using Newtonsoft.Json.Linq; +using WalletFramework.Core.ClaimPaths; using WalletFramework.Core.Functional; using WalletFramework.Core.Json; using WalletFramework.SdJwtVc.Models; using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.CredentialConfiguration; using static WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.SdJwt.SdJwtConfiguration.SdJwtConfigurationJsonKeys; -using ClaimMetadata = WalletFramework.SdJwtVc.Models.Credential.Attributes.ClaimMetadata; namespace WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.SdJwt; @@ -16,16 +16,6 @@ public record SdJwtConfiguration public Vct Vct { get; } - /// - /// Gets or sets the dictionary representing the attributes of the credential in different languages. - /// - public Dictionary? Claims { get; set; } - - /// - /// A list of claim display names, arranged in the order in which they should be displayed by the Wallet. - /// - public List? Order { get; set; } - private SdJwtConfiguration(CredentialConfiguration credentialConfiguration, Vct vct) { CredentialConfiguration = credentialConfiguration; @@ -37,95 +27,29 @@ private static SdJwtConfiguration Create(CredentialConfiguration credentialConfi public static Validation ValidSdJwtCredentialConfiguration(JToken config) { - var credentialConfiguration = ValidCredentialConfiguration(config); - var vct = config.GetByKey(VctJsonName).OnSuccess(Vct.ValidVct); - - var order = config[OrderJsonName]?.ToObject>(); - - var claimToken = config[ClaimsJsonName]; - var claimMetadatas = claimToken switch + var sdJwtClaimPathValidation = new Func>(token => { - //Used to map the ListRepresentation from Vci Draft15 to DictionaryRepresentation of Draft14 and older - JArray => ConvertToDictionaryRepresentation(claimToken.ToObject>()), - JObject => claimToken.ToObject>(), - _ => new Dictionary() - }; - - var result = ValidationFun.Valid(Create) - .Apply(credentialConfiguration) - .Apply(vct) - .OnSuccess(configuration => configuration with - { - Claims = claimMetadatas, - Order = order - }); + var sdJwtClaimPath = + from jArray in token.ToJArray() + from validClaimPath in ClaimPath.FromJArray(jArray) + select validClaimPath; - return result; - } - - private static Dictionary ConvertToDictionaryRepresentation(List? claimsV2) - { - var result = new Dictionary(); - - if (claimsV2 == null) - return result; + return sdJwtClaimPath; + }); - foreach (var claim in claimsV2) - { - if (claim.Path == null || claim.Path.Count == 0) - continue; + var credentialConfiguration = ValidCredentialConfiguration(config, sdJwtClaimPathValidation); + var vct = config.GetByKey(VctJsonName).OnSuccess(Vct.ValidVct); - AddToNestedClaims(result, claim.Path, claim); - } + var result = ValidationFun.Valid(Create) + .Apply(credentialConfiguration) + .Apply(vct); return result; } - - private static void AddToNestedClaims(Dictionary currentLevel, List path, ClaimMetadata sourceClaim) - { - var key = path[0]; - if (!currentLevel.TryGetValue(key, out var claimMetadata)) - { - claimMetadata = new ClaimMetadata(); - currentLevel[key] = claimMetadata; - } - - var isLeafClaim = path.Count == 1; - if (isLeafClaim) - { - claimMetadata.Display = sourceClaim.Display; - claimMetadata.ValueType = sourceClaim.ValueType; - claimMetadata.Mandatory = sourceClaim.Mandatory; - } - else - { - var nextKey = path[1]; - - if (claimMetadata.NestedClaims == null) - claimMetadata.NestedClaims = new Dictionary(); - - if (!claimMetadata.NestedClaims.TryGetValue(nextKey, out var nextToken) || nextToken.Type != JTokenType.Object) - { - var childNode = new ClaimMetadata - { - NestedClaims = new Dictionary() - }; - - claimMetadata.NestedClaims[nextKey] = JObject.FromObject(childNode); - } - - var nextNode = claimMetadata.NestedClaims[nextKey].ToObject()!; - AddToNestedClaims(new Dictionary { [nextKey] = nextNode }, path.Skip(1).ToList(), sourceClaim); - - claimMetadata.NestedClaims[nextKey] = JObject.FromObject(nextNode); - } - } public static class SdJwtConfigurationJsonKeys { public const string VctJsonName = "vct"; - public const string ClaimsJsonName = "claims"; - public const string OrderJsonName = "order"; } } @@ -136,39 +60,7 @@ public static JObject EncodeToJson(this SdJwtConfiguration config) var credentialConfig = config.CredentialConfiguration.EncodeToJson(); credentialConfig.Add(VctJsonName, config.Vct.ToString()); - - if (config.Claims is not null) - { - credentialConfig.Add(ClaimsJsonName, JObject.FromObject(config.Claims)); - } - - if (config.Order is not null) - { - credentialConfig.Add(OrderJsonName, JArray.FromObject(config.Order)); - } return credentialConfig; } - - public static Dictionary ExtractClaimMetadata(this SdJwtConfiguration sdJwtConfiguration) - { - return sdJwtConfiguration - .Claims? - .Where(x => !string.IsNullOrWhiteSpace(x.Key) && x.Value.Display is not null) - .SelectMany(claimMetadata => - { - var claimMetadatas = new Dictionary { { claimMetadata.Key, claimMetadata.Value } }; - - if (claimMetadata.Value.NestedClaims == null || claimMetadata.Value.NestedClaims.Count == 0) - return claimMetadatas; - - foreach (var nested in claimMetadata.Value.NestedClaims!) - { - claimMetadatas.Add(claimMetadata.Key + "." + nested.Key, nested.Value?.ToObject()!); - } - - return claimMetadatas; - }) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? new Dictionary(); - } } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/CredOffer/Models/CredentialConfigurationId.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/CredOffer/Models/CredentialConfigurationId.cs index db4ea1b6..07c2d818 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/CredOffer/Models/CredentialConfigurationId.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/CredOffer/Models/CredentialConfigurationId.cs @@ -6,7 +6,7 @@ namespace WalletFramework.Oid4Vc.Oid4Vci.CredOffer.Models; -public readonly struct CredentialConfigurationId +public readonly record struct CredentialConfigurationId { private string Value { get; } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocCandidateService.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocCandidateService.cs index acffce80..2fe99df6 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocCandidateService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocCandidateService.cs @@ -1,23 +1,26 @@ using LanguageExt; +using WalletFramework.Core.Credentials; using WalletFramework.Core.Functional; using WalletFramework.MdocLib.Device.Request; using WalletFramework.MdocVc; using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; +using WalletFramework.MdocVc.Persistence; +using WalletFramework.Storage; namespace WalletFramework.Oid4Vc.Oid4Vci.Implementations; -public class MdocCandidateService(IMdocStorage mdocStorage) : IMdocCandidateService +public class MdocCandidateService( + IDomainRepository repository) : IMdocCandidateService { - public async Task>> GetCandidates(DeviceRequest deviceRequest) + public async Task>> GetCandidates(DeviceRequest deviceRequest) { var first = deviceRequest.DocRequests.First(); var docType = first.ItemsRequest.DocType; // TODO: refactor with search query and constraint with items - var mdocsOption = await mdocStorage.ListAll(); + var mdocsOption = await repository.ListAll(); var mdocs = mdocsOption.UnwrapOrThrow(); - var candidates = mdocs.Where(record => record.DocType == docType); - var result = Option>.Some(candidates); - return result; + var candidates = mdocs.Where(c => c.Mdoc.DocType == docType); + return candidates.ToList(); } } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocFun.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocFun.cs index 61eb2095..e69de29b 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocFun.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocFun.cs @@ -1,40 +0,0 @@ -using LanguageExt; -using WalletFramework.MdocVc; -using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.Mdoc; - -namespace WalletFramework.Oid4Vc.Oid4Vci.Implementations; - -public static class MdocFun -{ - public static Option> CreateMdocDisplays(MdocConfiguration configuration) - { - var claimsDisplays = - from claimsMetadata in configuration.Claims - from dict in claimsMetadata.ToClaimsDisplays() - select dict; - - var credentialConfigurationDisplay = configuration.CredentialConfiguration.Display; - var result = - from credentialDisplays in credentialConfigurationDisplay - let mdocDisplays = credentialDisplays.Select(credentialDisplay => - { - var logo = - from credentialLogo in credentialDisplay.Logo - select new MdocLogo(credentialLogo.Uri); - - var mdocName = - from credentialName in credentialDisplay.Name - from name in MdocName.OptionMdocName(credentialName.ToString()) - select name; - - var backgroundColor = credentialDisplay.BackgroundColor; - var textColor = credentialDisplay.TextColor; - var locale = credentialDisplay.Locale; - - return new MdocDisplay(logo, mdocName, backgroundColor, textColor, locale, claimsDisplays); - }).ToList() - select mdocDisplays; - - return result; - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocStorage.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocStorage.cs deleted file mode 100644 index f476ee68..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/MdocStorage.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; -using LanguageExt; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Functional; -using WalletFramework.MdocVc; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; - -namespace WalletFramework.Oid4Vc.Oid4Vci.Implementations; - -public class MdocStorage : IMdocStorage -{ - public MdocStorage(IAgentProvider agentProvider, IWalletRecordService recordService) - { - _agentProvider = agentProvider; - _recordService = recordService; - } - - private readonly IAgentProvider _agentProvider; - private readonly IWalletRecordService _recordService; - - public async Task Add(MdocRecord record) - { - var context = await _agentProvider.GetContextAsync(); - await _recordService.AddAsync(context.Wallet, record); - return Unit.Default; - } - - public async Task> Get(CredentialId id) - { - var context = await _agentProvider.GetContextAsync(); - return await _recordService.GetAsync(context.Wallet, id); - } - - public async Task>> List( - Option query, - int count = 100, - int skip = 0) - { - var context = await _agentProvider.GetContextAsync(); - var list = await _recordService.SearchAsync( - context.Wallet, - query.ToNullable(), - null, - count, - skip); - - if (list.Count == 0) - return Option>.None; - - return list; - } - - public async Task>> List(CredentialSetId id) - { - var query = SearchQuery.Equal( - "~" + nameof(MdocRecord.CredentialSetId), - id); - - var some = Option.Some(query); - return await List(some); - } - - public async Task Update(MdocRecord record) - { - var context = await _agentProvider.GetContextAsync(); - await _recordService.Update(context.Wallet, record); - return Unit.Default; - } - - public async Task Delete(MdocRecord record) - { - var context = await _agentProvider.GetContextAsync(); - await _recordService.Delete(context.Wallet, record); - return Unit.Default; - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/Oid4VciClientService.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/Oid4VciClientService.cs index 4bb6b649..d781975a 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/Oid4VciClientService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/Oid4VciClientService.cs @@ -1,10 +1,8 @@ using System.Security.Cryptography; using System.Text; -using Hyperledger.Aries.Agents; using LanguageExt; using Microsoft.IdentityModel.Tokens; using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Abstractions; using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; using WalletFramework.Oid4Vc.Oid4Vci.Authorization.Abstractions; using WalletFramework.Oid4Vc.Oid4Vci.Authorization.Models; @@ -19,84 +17,62 @@ using WalletFramework.Core.Localization; using WalletFramework.Core.String; using WalletFramework.MdocLib; -using WalletFramework.MdocVc; using WalletFramework.Oid4Vc.ClientAttestation; -using WalletFramework.Oid4Vc.CredentialSet; using WalletFramework.Oid4Vc.CredentialSet.Models; using WalletFramework.Oid4Vc.Oid4Vci.Authorization.DPop.Models; using WalletFramework.Oid4Vc.Oid4Vci.CredentialNonce.Abstractions; using WalletFramework.Oid4Vc.Oid4Vp.Models; using WalletFramework.SdJwtVc.Models; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; using static Newtonsoft.Json.JsonConvert; +using WalletFramework.Oid4Vc.CredentialSet.Persistence; +using WalletFramework.Core.Credentials; +using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; +using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Persistence; +using WalletFramework.Storage; namespace WalletFramework.Oid4Vc.Oid4Vci.Implementations; -/// -public class Oid4VciClientService : IOid4VciClientService +/// +/// Initializes a new instance of the class. +/// +/// The authorization flow session storage service. +/// The client attestation service. +/// The credential offer service. +/// The credential request service. +/// The repository for storing credential data sets. +/// The repository for storing SD-JWT credentials. +/// The repository for storing mDOC credentials. +/// The factory to create HTTP client instances. +/// The issuer metadata service. +/// The credential nonce service. +/// The token service. +public class Oid4VciClientService( + IClientAttestationService clientAttestationService, + ICredentialNonceService credentialNonceService, + ICredentialOfferService credentialOfferService, + ICredentialRequestService credentialRequestService, + IDomainRepository authFlowSessionRepository, + IDomainRepository credentialDataSetRepository, + IDomainRepository mdocCredentialRepository, + IDomainRepository sdJwtCredentialRepository, + IHttpClientFactory httpClientFactory, + IIssuerMetadataService issuerMetadataService, + ITokenService tokenService) : IOid4VciClientService { private const string AuthorizationCodeGrantTypeIdentifier = "authorization_code"; private const string PreAuthorizedCodeGrantTypeIdentifier = "urn:ietf:params:oauth:grant-type:pre-authorized_code"; - /// - /// Initializes a new instance of the class. - /// - /// - /// The credential request service. - /// - /// - /// The factory to create instances of . Used for making HTTP - /// requests. - /// - /// The authorization record service - /// - /// The token service. - /// - /// - /// - public Oid4VciClientService( - IAgentProvider agentProvider, - IAuthFlowSessionStorage authFlowSessionAuthFlowSessionStorage, - IClientAttestationService clientAttestationService, - ICredentialOfferService credentialOfferService, - ICredentialRequestService credentialRequestService, - ICredentialSetStorage credentialSetStorage, - IHttpClientFactory httpClientFactory, - IIssuerMetadataService issuerMetadataService, - IMdocStorage mdocStorage, - ISdJwtVcHolderService sdJwtService, - ICredentialNonceService credentialNonceService, - ITokenService tokenService) - { - _agentProvider = agentProvider; - _authFlowSessionStorage = authFlowSessionAuthFlowSessionStorage; - _clientAttestationService = clientAttestationService; - _credentialOfferService = credentialOfferService; - _credentialRequestService = credentialRequestService; - _credentialSetStorage = credentialSetStorage; - _httpClient = httpClientFactory.CreateClient(); - _issuerMetadataService = issuerMetadataService; - _mdocStorage = mdocStorage; - _sdJwtService = sdJwtService; - _credentialNonceService = credentialNonceService; - _tokenService = tokenService; - } + private readonly HttpClient _httpClient = httpClientFactory.CreateClient(); - private readonly HttpClient _httpClient; - private readonly IAgentProvider _agentProvider; - private readonly IAuthFlowSessionStorage _authFlowSessionStorage; - private readonly IClientAttestationService _clientAttestationService; - private readonly ICredentialOfferService _credentialOfferService; - private readonly ICredentialRequestService _credentialRequestService; - private readonly ICredentialSetStorage _credentialSetStorage; - private readonly IIssuerMetadataService _issuerMetadataService; - private readonly IMdocStorage _mdocStorage; - private readonly ISdJwtVcHolderService _sdJwtService; - private readonly ICredentialNonceService _credentialNonceService; - private readonly ITokenService _tokenService; - /// - public async Task InitiateAuthFlow(CredentialOfferMetadata offer, ClientOptions clientOptions, Option clientAttestationDetails) + public async Task InitiateAuthFlow( + CredentialOfferMetadata offer, + ClientOptions clientOptions, + Option clientAttestationDetails) { var authorizationCodeParameters = CreateAndStoreCodeChallenge(); var sessionId = AuthFlowSessionState.CreateAuthFlowSessionState(); @@ -119,11 +95,11 @@ public async Task InitiateAuthFlow(CredentialOfferMetadata offer, ClientOpt .CredentialConfigurationsSupported .Where(config => offer.CredentialOffer.CredentialConfigurationIds.Contains(config.Key)) .Select(pair => pair.Value.Match( - sdJwt => new AuthorizationDetails( + _ => new AuthorizationDetails( pair.Key.ToString(), issuerMetadata.AuthorizationServers.ToNullable()?.Select(id => id.ToString()).ToArray() ), - mdoc => new AuthorizationDetails( + _ => new AuthorizationDetails( pair.Key.ToString(), issuerMetadata.AuthorizationServers.ToNullable()?.Select(id => id.ToString()).ToArray()) ) @@ -162,13 +138,13 @@ from issState in code.IssuerState Option.None, offer.CredentialOffer.CredentialConfigurationIds); - var context = await _agentProvider.GetContextAsync(); - await _authFlowSessionStorage.StoreAsync( - context, + var session = new AuthFlowSession( + sessionId, authorizationData, authorizationCodeParameters, - sessionId, Option.None); + + await authFlowSessionRepository.Add(session); return authorizationRequestUri; } @@ -179,7 +155,7 @@ public async Task InitiateAuthFlow(Uri uri, ClientOptions clientOptions, Op some => some, () => Core.Localization.Constants.DefaultLocale); - var issuerMetadata = _issuerMetadataService.ProcessMetadata(uri, locale); + var issuerMetadata = issuerMetadataService.ProcessMetadata(uri, locale); return await issuerMetadata.Match( async validIssuerMetadata => @@ -239,17 +215,17 @@ public async Task InitiateAuthFlow(Uri uri, ClientOptions clientOptions, Op .Select(config => config.Key) .ToList()); - var context = await _agentProvider.GetContextAsync(); - await _authFlowSessionStorage.StoreAsync( - context, + var session = new AuthFlowSession( + sessionId, authorizationData, authorizationCodeParameters, - sessionId, specVersion); + + await authFlowSessionRepository.Add(session); return authorizationRequestUri; }, - _ => throw new Exception("Fetching Issuer metadata failed") + _ => throw new InvalidOperationException("Fetching Issuer metadata failed") ); } @@ -259,7 +235,7 @@ private async Task GetRequestUriUsingPushedAuthorizationRequest(Authorizati await clientAttestationDetails.IfSomeAsync(async attestationDetails => { - var combinedWalletAttestation = await _clientAttestationService.GetCombinedWalletAttestationAsync(attestationDetails, authorizationServerMetadata); + var combinedWalletAttestation = await clientAttestationService.GetCombinedWalletAttestationAsync(attestationDetails, authorizationServerMetadata); _httpClient.AddClientAttestationPopHeader(combinedWalletAttestation); }); @@ -276,7 +252,10 @@ await clientAttestationDetails.IfSomeAsync(async attestationDetails => + "&request_uri=" + System.Net.WebUtility.UrlEncode(parResponse.RequestUri.ToString())); } - public async Task>> AcceptOffer(CredentialOfferMetadata credentialOfferMetadata, Option clientAttestationDetails, string? transactionCode) + public async Task>> AcceptOffer( + CredentialOfferMetadata credentialOfferMetadata, + Option clientAttestationDetails, + string? transactionCode) { var issuerMetadata = credentialOfferMetadata.IssuerMetadata; @@ -294,7 +273,7 @@ from preAuthCode in grants.PreAuthorizedCode var authorizationServerMetadata = await FetchAuthorizationServerMetadataAsync(issuerMetadata, credentialOfferMetadata.CredentialOffer); - var token = await _tokenService.RequestToken( + var token = await tokenService.RequestToken( tokenRequest, authorizationServerMetadata, clientAttestationDetails, @@ -304,7 +283,7 @@ from preAuthCode in grants.PreAuthorizedCode var configurationId = credentialOfferMetadata.CredentialOffer.CredentialConfigurationIds.First(); var configurationPair = issuerMetadata.CredentialConfigurationsSupported.Single(config => config.Key == configurationId); - var validResponses = await _credentialRequestService.RequestCredentials( + var validResponses = await credentialRequestService.RequestCredentials( configurationPair, issuerMetadata, token, @@ -312,58 +291,58 @@ from preAuthCode in grants.PreAuthorizedCode Option.None, Option.None); - var credentialSets = new List(); + var credentialSets = new List(); var result = from responses in validResponses - let credentialSet = new CredentialSetRecord() + let setId = CredentialSetId.CreateCredentialSetId() select from response in responses let credentialsOrTransactionId = response.CredentialsOrTransactionId select credentialsOrTransactionId.Match( async creds => { + var records = new List(); foreach (var credential in creds) { await credential.Value.Match( async sdJwt => { - var record = sdJwt.Decoded.ToRecord( - configurationPair.Value.AsT0, + var record = sdJwt.Decoded.ToCredential( response.KeyId, - credentialSet.CredentialSetId, + setId, creds.Count > 1); - var context = await _agentProvider.GetContextAsync(); - await _sdJwtService.AddAsync(context, record); - - credentialSet.AddSdJwtData(record); + await sdJwtCredentialRepository.Add(record); + records.Add(record); }, async mdoc => { - var displays = MdocFun.CreateMdocDisplays(configurationPair.Value.AsT1); - - var record = mdoc.Decoded.ToRecord( - displays, + var mdocCredential = new MdocCredential( + mdoc.Decoded, + CredentialId.CreateCredentialId(), + setId, response.KeyId.UnwrapOrThrow(), - credentialSet.CredentialSetId, - creds.Count > 1); + CredentialState.Active, + creds.Count > 1, + Option.None); - await _mdocStorage.Add(record); - - credentialSet.AddMDocData(record, issuerMetadata.CredentialIssuer); + await mdocCredentialRepository.Add(mdocCredential); + records.Add(mdocCredential); }); } - credentialSets.Add(credentialSet); + + var dataSet = CredentialDataSet.FromCredentials( + records, + issuerMetadata.CredentialIssuer.ToString()); + + credentialSets.Add(dataSet); }, // ReSharper disable once UnusedParameter.Local transactionId => throw new NotImplementedException()); await result.OnSuccess(async tasks => await Task.WhenAll(tasks)); - foreach (var credentialSet in credentialSets) - { - await _credentialSetStorage.Add(credentialSet); - } + await credentialDataSetRepository.AddMany(credentialSets); return credentialSets; } @@ -375,19 +354,20 @@ public async Task> ProcessOffer(Uri credenti () => Core.Localization.Constants.DefaultLocale); var result = - from offer in _credentialOfferService.ProcessCredentialOffer(credentialOffer, locale) - from metadata in _issuerMetadataService.ProcessMetadata(offer.CredentialIssuer, locale) + from offer in credentialOfferService.ProcessCredentialOffer(credentialOffer, locale) + from metadata in issuerMetadataService.ProcessMetadata(offer.CredentialIssuer, locale) select new CredentialOfferMetadata(offer, metadata); return await result; } /// - public async Task>> RequestCredentialSet(IssuanceSession issuanceSession, Option clientAttestationDetails) + public async Task>> RequestCredentialSet( + IssuanceSession issuanceSession, + Option clientAttestationDetails) { - var context = await _agentProvider.GetContextAsync(); - - var session = await _authFlowSessionStorage.GetAsync(context, issuanceSession.AuthFlowSessionState); + var session = (await authFlowSessionRepository.GetById(issuanceSession.AuthFlowSessionState)) + .UnwrapOrThrow(new InvalidOperationException("Auth flow session not found")); var relevantConfigurations = session .AuthorizationData @@ -395,7 +375,9 @@ public async Task>> RequestCredentia .CredentialConfigurationsSupported .Where(config => session.AuthorizationData.CredentialConfigurationIds.Contains(config.Key)); - var scopes = relevantConfigurations + var configurations = relevantConfigurations.ToList(); + + var scopes = configurations .Select(config => config.Value.Match( sdJwtConfig => sdJwtConfig.CredentialConfiguration.Scope.OnSome(scope => scope.ToString()), mdDocConfig => mdDocConfig.CredentialConfiguration.Scope.OnSome(scope => scope.ToString()))) @@ -412,17 +394,19 @@ public async Task>> RequestCredentia ClientId = session.AuthorizationData.ClientOptions.ClientId }; - var token = await _tokenService.RequestToken( + var token = await tokenService.RequestToken( tokenRequest, session.AuthorizationData.AuthorizationServerMetadata, clientAttestationDetails, session.AuthorizationData.IssuerMetadata.CredentialNonceEndpoint); //TODO: Make sure that it does not always request all available credConfigurations - var credentialSets = new List(); - foreach (var configuration in relevantConfigurations) + var credentialSets = new List(); + var records = new List(); + var setId = CredentialSetId.CreateCredentialSetId(); + foreach (var configuration in configurations) { - var validResponses = await _credentialRequestService.RequestCredentials( + var validResponses = await credentialRequestService.RequestCredentials( configuration, session.AuthorizationData.IssuerMetadata, token, @@ -432,7 +416,6 @@ public async Task>> RequestCredentia var result = from responses in validResponses - let credentialSet = new CredentialSetRecord() select from response in responses let cNonce = response.CNonce @@ -443,7 +426,7 @@ select credentialsOrTransactionId.Match( token = await session.AuthorizationData.IssuerMetadata.CredentialNonceEndpoint.Match( Some: async credentialNonceEndpoint => { - var credentialNonce = await _credentialNonceService.GetCredentialNonce(credentialNonceEndpoint); + var credentialNonce = await credentialNonceService.GetCredentialNonce(credentialNonceEndpoint); return token.Match>( oAuth => oAuth with { CNonce = credentialNonce.Value }, dPop => dPop with @@ -453,59 +436,74 @@ select credentialsOrTransactionId.Match( }, None: () => { - return Task.FromResult>( token.Match>( + return Task.FromResult( token.Match>( oAuth => oAuth with { CNonce = cNonce.ToNullable() }, dPop => dPop with { Token = dPop.Token with { CNonce = cNonce.ToNullable() } })); }); + + if (configurations.Count == 1) + { + records = []; + setId = CredentialSetId.CreateCredentialSetId(); + } foreach (var credential in creds) { await credential.Value.Match( async sdJwt => { - var record = sdJwt.Decoded.ToRecord( - configuration.Value.AsT0, + var record = sdJwt.Decoded.ToCredential( response.KeyId, - credentialSet.CredentialSetId, + setId, creds.Count > 1); - await _sdJwtService.AddAsync(context, record); - - credentialSet.AddSdJwtData(record); - // credentialSets.Add(credentialSet); + await sdJwtCredentialRepository.Add(record); + records.Add(record); }, async mdoc => { - var displays = MdocFun.CreateMdocDisplays(configuration.Value.AsT1); - - var record = mdoc.Decoded.ToRecord( - displays, + var mdocCredential = new MdocCredential( + mdoc.Decoded, + CredentialId.CreateCredentialId(), + setId, response.KeyId.UnwrapOrThrow(), - credentialSet.CredentialSetId, - creds.Count > 1); + CredentialState.Active, + creds.Count > 1, + Option.None); - await _mdocStorage.Add(record); - - credentialSet.AddMDocData(record, session.AuthorizationData.IssuerMetadata.CredentialIssuer); + await mdocCredentialRepository.Add(mdocCredential); + records.Add(mdocCredential); }); } - credentialSets.Add(credentialSet); + + if (configurations.Count == 1) + { + var dataSet = CredentialDataSet.FromCredentials( + records, + session.AuthorizationData.IssuerMetadata.CredentialIssuer.ToString()); + credentialSets.Add(dataSet); + } }, // ReSharper disable once UnusedParameter.Local transactionId => throw new NotImplementedException()); await result.OnSuccess(async tasks => await Task.WhenAll(tasks)); } - - foreach (var credentialSet in credentialSets) + + if (configurations.Count > 1) { - await _credentialSetStorage.Add(credentialSet); + var dataSet = CredentialDataSet.FromCredentials( + records, + session.AuthorizationData.IssuerMetadata.CredentialIssuer.ToString()); + credentialSets.Add(dataSet); } - await _authFlowSessionStorage.DeleteAsync(context, session.AuthFlowSessionState); + await credentialDataSetRepository.AddMany(credentialSets); + + await authFlowSessionRepository.Delete(session.AuthFlowSessionState); return credentialSets; } @@ -514,17 +512,17 @@ await credential.Value.Match( /// public async Task>> RequestOnDemandCredentialSet(IssuanceSession issuanceSession, AuthorizationRequest authorizationRequest, Option clientAttestationDetails) { - var context = await _agentProvider.GetContextAsync(); - - var session = await _authFlowSessionStorage.GetAsync(context, issuanceSession.AuthFlowSessionState); + var session = (await authFlowSessionRepository.GetById(issuanceSession.AuthFlowSessionState)) + .UnwrapOrThrow(new InvalidOperationException("Auth flow session not found")); var relevantConfigurations = session .AuthorizationData .IssuerMetadata .CredentialConfigurationsSupported .Where(config => session.AuthorizationData.CredentialConfigurationIds.Contains(config.Key)); - - var scopes = relevantConfigurations + + var configurations = relevantConfigurations.ToList(); + var scopes = configurations .Select(config => config.Value.Match( sdJwtConfig => sdJwtConfig.CredentialConfiguration.Scope.OnSome(scope => scope.ToString()), mdDocConfig => mdDocConfig.CredentialConfiguration.Scope.OnSome(scope => scope.ToString()))) @@ -541,18 +539,18 @@ public async Task>> RequestOnDeman ClientId = session.AuthorizationData.ClientOptions.ClientId }; - var token = await _tokenService.RequestToken( + var token = await tokenService.RequestToken( tokenRequest, session.AuthorizationData.AuthorizationServerMetadata, clientAttestationDetails, session.AuthorizationData.IssuerMetadata.CredentialNonceEndpoint); - var credentials = new List<(CredentialSetRecord, List)>(); + var credentials = new List<(CredentialDataSet, List)>(); //TODO: Make sure that it does not always request all available credConfigurations - foreach (var configuration in relevantConfigurations) + foreach (var configuration in configurations) { - var validResponses = await _credentialRequestService.RequestCredentials( + var validResponses = await credentialRequestService.RequestCredentials( configuration, session.AuthorizationData.IssuerMetadata, token, @@ -562,7 +560,7 @@ public async Task>> RequestOnDeman var result = from responses in validResponses - let credentialSet = new CredentialSetRecord() + let setId = CredentialSetId.CreateCredentialSetId() select from response in responses let cNonce = response.CNonce @@ -573,14 +571,12 @@ select credentialsOrTransactionId.Match( token = await session.AuthorizationData.IssuerMetadata.CredentialNonceEndpoint.Match( Some: async credentialNonceEndpoint => { - var credentialNonce = await _credentialNonceService.GetCredentialNonce(credentialNonceEndpoint); + var credentialNonce = await credentialNonceService.GetCredentialNonce(credentialNonceEndpoint); return token.Match>( oAuth => { - session.AuthorizationData = session.AuthorizationData with - { - OAuthToken = oAuth - }; + var newAuthData = session.AuthorizationData with { OAuthToken = oAuth }; + session = session with { AuthorizationData = newAuthData }; return oAuth with { @@ -589,10 +585,8 @@ select credentialsOrTransactionId.Match( }, dPop => { - session.AuthorizationData = session.AuthorizationData with - { - OAuthToken = dPop.Token - }; + var newAuthData2 = session.AuthorizationData with { OAuthToken = dPop.Token }; + session = session with { AuthorizationData = newAuthData2 }; return dPop with { @@ -602,22 +596,18 @@ select credentialsOrTransactionId.Match( }, None: () => { - return Task.FromResult>( token.Match>( + return Task.FromResult(token.Match>( oAuth => { - session.AuthorizationData = session.AuthorizationData with - { - OAuthToken = oAuth - }; + var newAuthData3 = session.AuthorizationData with { OAuthToken = oAuth }; + session = session with { AuthorizationData = newAuthData3 }; return oAuth with { CNonce = cNonce.ToNullable() }; }, dPop => { - session.AuthorizationData = session.AuthorizationData with - { - OAuthToken = dPop.Token - }; + var newAuthData4 = session.AuthorizationData with { OAuthToken = dPop.Token }; + session = session with { AuthorizationData = newAuthData4 }; return dPop with { @@ -632,58 +622,52 @@ select credentialsOrTransactionId.Match( var record = credential.Value.Match( sdJwt => { - var record = sdJwt.Decoded.ToRecord( - configuration.Value.AsT0, + var record = sdJwt.Decoded.ToCredential( response.KeyId, - credentialSet.CredentialSetId, + setId, creds.Count > 1); - - credentialSet.AddSdJwtData(record); - + records.Add(record); return record; }, mdoc => { - var displays = MdocFun.CreateMdocDisplays(configuration.Value.AsT1); - - var record = mdoc.Decoded.ToRecord( - displays, + var mdocCredential = new MdocCredential( + mdoc.Decoded, + CredentialId.CreateCredentialId(), + setId, response.KeyId.UnwrapOrThrow(), - credentialSet.CredentialSetId, - creds.Count > 1); - - credentialSet.AddMDocData(record, session.AuthorizationData.IssuerMetadata.CredentialIssuer); - - return record; + CredentialState.Active, + creds.Count > 1, + Option.None); + records.Add(mdocCredential); + return mdocCredential; }); records.Add(record); } - credentials.Add((credentialSet, records)); + var dataSet = CredentialDataSet.FromCredentials( + records, + session.AuthorizationData.IssuerMetadata.CredentialIssuer.ToString()); + credentials.Add((dataSet, records)); }, // ReSharper disable once UnusedParameter.Local transactionId => throw new NotImplementedException()); - await result.OnSuccess(async tasks => await Task.WhenAll(tasks)); + await result.OnSuccess(Task.WhenAll); } - await _authFlowSessionStorage.UpdateAsync(context, session); + await authFlowSessionRepository.Update(session); return credentials.Select(credential => new OnDemandCredentialSet(credential.Item1, credential.Item2)).ToList(); } private static AuthorizationCodeParameters CreateAndStoreCodeChallenge() { - var rng = new RNGCryptoServiceProvider(); - var randomNumber = new byte[32]; - rng.GetBytes(randomNumber); - + var randomNumber = RandomNumberGenerator.GetBytes(32); var codeVerifier = Base64UrlEncoder.Encode(randomNumber); - var sha256 = SHA256.Create(); - var bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); - + var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(codeVerifier)); var codeChallenge = Base64UrlEncoder.Encode(bytes); return new AuthorizationCodeParameters(codeChallenge, codeVerifier); @@ -769,7 +753,7 @@ from code in grants.PreAuthorizedCode ?? authorizationServerMetadatas.FirstOrDefault() ?? throw new InvalidOperationException("No suitable Authorization Server found")); }, - None: () => authorizationServerMetadatas.First()); + None: () => authorizationServerMetadatas[0]); }); }, None: () => authorizationServerMetadatas.Find(authServer => authServer.SupportsAuthCodeFlow) diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/SdJwtCredentialExtensions.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/SdJwtCredentialExtensions.cs new file mode 100644 index 00000000..e6bf16a4 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/SdJwtCredentialExtensions.cs @@ -0,0 +1,33 @@ +using LanguageExt; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.SdJwtLib.Models; +using WalletFramework.SdJwtVc; + +namespace WalletFramework.Oid4Vc.Oid4Vci.Implementations; + +public static class SdJwtCredentialExtensions +{ + public static SdJwtCredential ToCredential( + this SdJwtDoc sdJwtDoc, + Option keyId, + CredentialSetId credentialSetId, + bool isOneTimeUse) + { + var expiresAt = sdJwtDoc.UnsecuredPayload.SelectToken("exp")?.Value() is { } exp + ? Option.Some(DateTimeOffset.FromUnixTimeSeconds(exp).DateTime) + : Option.None; + + var credential = new SdJwtCredential( + sdJwtDoc, + CredentialId.CreateCredentialId(), + credentialSetId, + keyId, + CredentialState.Active, + isOneTimeUse, + expiresAt); + + return credential; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/SdJwtRecordExtensions.cs b/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/SdJwtRecordExtensions.cs deleted file mode 100644 index 70cd2419..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/SdJwtRecordExtensions.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Drawing; -using LanguageExt; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Cryptography.Models; -using WalletFramework.Core.Functional; -using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.SdJwt; -using WalletFramework.SdJwtLib.Models; -using WalletFramework.SdJwtVc.Models.Credential; -using WalletFramework.SdJwtVc.Models.Records; - -namespace WalletFramework.Oid4Vc.Oid4Vci.Implementations; - -public static class SdJwtRecordExtensions -{ - public static SdJwtRecord ToRecord( - this SdJwtDoc sdJwtDoc, - SdJwtConfiguration configuration, - Option keyId, - CredentialSetId credentialSetId, - bool isOneTimeUse) - { - var claims = configuration.ExtractClaimMetadata(); - - var display = - from displays in configuration.CredentialConfiguration.Display - select displays.Select(credentialDisplay => - { - var backgroundColor = credentialDisplay.BackgroundColor.ToNullable() ?? Color.White; - var textColor = credentialDisplay.TextColor.ToNullable() ?? Color.Black; - - return new SdJwtDisplay - { - Logo = new SdJwtDisplay.SdJwtLogo - { - AltText = credentialDisplay.Logo.ToNullable()?.AltText.ToNullable(), - Uri = credentialDisplay.Logo.ToNullable()?.Uri! - }, - Name = credentialDisplay.Name.ToNullable(), - BackgroundColor = backgroundColor, - Locale = credentialDisplay.Locale.ToNullable(), - TextColor = textColor - }; - }).ToList(); - - var record = new SdJwtRecord( - sdJwtDoc, - claims, - display.Fallback([]), - keyId, - credentialSetId, - isOneTimeUse); - - return record; - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponse.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponse.cs index 9f30897a..376a4a5d 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponse.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponse.cs @@ -1,4 +1,3 @@ -using Hyperledger.Aries.Extensions; using Jose; using LanguageExt; using Microsoft.IdentityModel.Tokens; @@ -7,6 +6,7 @@ using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using WalletFramework.Core.Base64Url; +using WalletFramework.Core.String; using WalletFramework.Oid4Vc.Oid4Vp.Jwk; using WalletFramework.Oid4Vc.Oid4Vp.Models; using static WalletFramework.Oid4Vc.Constants; @@ -33,7 +33,7 @@ public static EncryptedAuthorizationResponse Encrypt( Option encryptedResponseEncAlgorithms, Option mdocNonce) { - var apvBase64 = Base64UrlString.CreateBase64UrlString(apv.GetUTF8Bytes()); + var apvBase64 = Base64UrlString.CreateBase64UrlString(apv.GetUtf8Bytes()); var headers = new Dictionary { @@ -56,7 +56,7 @@ public static EncryptedAuthorizationResponse Encrypt( () => DefaultResponseEncryptionEncAlgorithm); var jwe = JWE.EncryptBytes( - response.ToJson().GetUTF8Bytes(), + response.ToJson().GetUtf8Bytes(), [new JweRecipient(JweAlgorithm.ECDH_ES, verifierPubKey.ToEcdh())], SupportedEncAlgorithmsMap[selectedEncAlgorithm], mode: SerializationMode.Compact, diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/CompletedPresentation.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/CompletedPresentation.cs new file mode 100644 index 00000000..47828c92 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/CompletedPresentation.cs @@ -0,0 +1,79 @@ +using LanguageExt; +using WalletFramework.Oid4Vc.Oid4Vp.Models; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Functional; +using WalletFramework.Core.Json; + +namespace WalletFramework.Oid4Vc.Oid4Vp; + +public record CompletedPresentation( + string PresentationId, + string ClientId, + List PresentedCredentialSets, + Option ClientMetadata, + Option Name, + DateTimeOffset LastTimeUsed); + +public static class CompletedPresentationExtensions +{ + private const string PresentationIdJsonKey = "PresentationId"; + private const string ClientIdJsonKey = "ClientId"; + private const string PresentedCredentialSetsJsonKey = "PresentedCredentialSets"; + private const string ClientMetadataJsonKey = "ClientMetadata"; + private const string NameJsonKey = "Name"; + private const string LastTimeUsedJsonKey = "LastTimeUsed"; + + public static JObject EncodeToJson(this CompletedPresentation presentation) + { + var result = new JObject + { + { PresentationIdJsonKey, presentation.PresentationId }, + { ClientIdJsonKey, presentation.ClientId } + }; + + var presentedSetsArray = new JArray(presentation.PresentedCredentialSets.Select(set => set.EncodeToJson())); + result.Add(PresentedCredentialSetsJsonKey, presentedSetsArray); + + presentation.ClientMetadata.IfSome(meta => result.Add(ClientMetadataJsonKey, JObject.FromObject(meta))); + presentation.Name.IfSome(name => result.Add(NameJsonKey, name)); + result.Add(LastTimeUsedJsonKey, presentation.LastTimeUsed); + + return result; + } + + public static string Serialize(this CompletedPresentation presentation) => presentation.EncodeToJson().ToString(); + + public static CompletedPresentation Deserialize(string json) + { + var jObject = JObject.Parse(json); + return DecodeFromJson(jObject); + } + + public static CompletedPresentation DecodeFromJson(JObject jObject) + { + var presentationId = jObject[PresentationIdJsonKey]!.ToString(); + var clientId = jObject[ClientIdJsonKey]!.ToString(); + + var setsToken = jObject[PresentedCredentialSetsJsonKey]!; + var setsArray = setsToken.ToObject()!; + var presentedSets = PresentedCredentialSetExtensions.DecodeFromJson(setsArray); + + var clientMetadata = + from token in jObject.GetByKey(ClientMetadataJsonKey).ToOption() + select token.ToObject()!; + + var name = + from token in jObject.GetByKey(NameJsonKey).ToOption() + select token.ToObject()!; + + var lastTimeUsed = jObject[LastTimeUsedJsonKey]!.ToObject(); + + return new CompletedPresentation( + presentationId, + clientId, + presentedSets, + clientMetadata, + name, + lastTimeUsed); + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Models/ClaimQuery.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Models/ClaimQuery.cs index 207be0e6..2acdebed 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Models/ClaimQuery.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Models/ClaimQuery.cs @@ -12,8 +12,7 @@ using WalletFramework.Oid4Vc.Oid4Vp.Dcql.CredentialQueries; using WalletFramework.Oid4Vc.RelyingPartyAuthentication.RegistrationCertificate; using WalletFramework.SdJwtLib.Models; -using WalletFramework.SdJwtVc.Models.Records; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; +using WalletFramework.SdJwtVc; using static WalletFramework.Oid4Vc.Oid4Vp.Dcql.Models.ClaimQueryConstants; namespace WalletFramework.Oid4Vc.Oid4Vp.Dcql.Models; @@ -83,7 +82,7 @@ public static Validation FromJObject(JObject json) return new StringIsNullOrWhitespaceError(); } - return ValidationFun.Valid(value.Value.ToString());; + return ValidationFun.Valid(value.Value.ToString()); })) .OnSuccess(array => array.TraverseAll(x => x)) .ToOption(); @@ -134,10 +133,10 @@ public static Validation FromJObject(JObject json) return ValidationFun.Valid(Create) .Apply(id) .Apply(path) - .Apply(values) + .Apply(values!) .Apply(purpose) - .Apply(@namespace) - .Apply(claimName); + .Apply(@namespace!) + .Apply(claimName!); } private static ClaimQuery Create( @@ -230,9 +229,9 @@ public static bool AreFulfilledBy(this IEnumerable? claims, ICredent switch (credential) { - case SdJwtRecord sdJwt: - return claims.AreFulfilledBy(sdJwt.ToSdJwtDoc()); - case MdocRecord mdoc: + case SdJwtCredential sdJwt: + return claims.AreFulfilledBy(sdJwt.SdJwtDoc); + case MdocCredential mdoc: return claims.AreFulfilledBy(mdoc.Mdoc); default: return false; diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Services/DcqlService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Services/DcqlService.cs index 2b7c84de..fa2dc17a 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Services/DcqlService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Dcql/Services/DcqlService.cs @@ -1,44 +1,49 @@ -using Hyperledger.Aries.Agents; using LanguageExt; -using Newtonsoft.Json.Linq; using WalletFramework.Core.Functional; using WalletFramework.Core.Credentials.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; using WalletFramework.Oid4Vc.Oid4Vp.AuthResponse; using WalletFramework.Oid4Vc.Oid4Vp.Dcql.CredentialQueries; using WalletFramework.Oid4Vc.Oid4Vp.Dcql.Models; using WalletFramework.Oid4Vc.Oid4Vp.Models; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; using static LanguageExt.Option; +using WalletFramework.Storage; +using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; +using WalletFramework.Core.Credentials; +using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Persistence; namespace WalletFramework.Oid4Vc.Oid4Vp.Dcql.Services; public class DcqlService( - IAgentProvider agentProvider, - IMdocStorage mdocStorage, - ISdJwtVcHolderService sdJwtVcHolderService) : IDcqlService + IDomainRepository mdocCredentialRepository, + IDomainRepository sdJwtCredentialRepository) : IDcqlService { public async Task Query(DcqlQuery query) { - var context = await agentProvider.GetContextAsync(); - var sdJwtRecords = await sdJwtVcHolderService.ListAsync(context); - var mdocsOption = await mdocStorage.ListAll(); + var sdJwtRecords = await sdJwtCredentialRepository.ListAll(); + var mdocsOption = await mdocCredentialRepository.ListAll(); + + var sdJwts = sdJwtRecords.ToNullable() ?? []; var mdocs = mdocsOption.ToNullable() ?? []; - var credentials = sdJwtRecords.Cast().Concat(mdocs); + var credentials = sdJwts.Cast().Concat(mdocs); return query.ProcessWith(credentials); } public async Task> QuerySingle(CredentialQuery query) { - var context = await agentProvider.GetContextAsync(); - var sdJwtRecords = await sdJwtVcHolderService.ListAsync(context); - var sdJwtCandidate = query.FindMatchingCandidate(sdJwtRecords); + var sdJwtRecords = await sdJwtCredentialRepository.ListAll(); + var sdJwtCandidate = + from record in sdJwtRecords + from candidate in query.FindMatchingCandidate(record) + select candidate; - var mdocRecords = await mdocStorage.ListAll(); - var mdocCandidate = from record in mdocRecords - from candidate in query.FindMatchingCandidate(record) - select candidate; + var mdocRecords = await mdocCredentialRepository.ListAll(); + var mdocCandidate = + from record in mdocRecords + from candidate in query.FindMatchingCandidate(record) + select candidate; return sdJwtCandidate.Match(Some, () => mdocCandidate); } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/AuthorizationRequestCancellation.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/AuthorizationRequestCancellation.cs index a56e658a..4b282fb9 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/AuthorizationRequestCancellation.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/AuthorizationRequestCancellation.cs @@ -4,9 +4,8 @@ namespace WalletFramework.Oid4Vc.Oid4Vp.Models; -public record AuthorizationRequestCancellation( - Option ResponseUri, - List Errors); +public record AuthorizationRequestCancellation(Option ResponseUri, List Errors) + : Error("Authorization request was cancelled"); public static class AuthorizationRequestCancellationFun { diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/OidPresentationRecord.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/OidPresentationRecord.cs deleted file mode 100644 index 1e6a72e7..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/OidPresentationRecord.cs +++ /dev/null @@ -1,168 +0,0 @@ -using Hyperledger.Aries.Storage; -using LanguageExt; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using WalletFramework.Core.Functional; -using WalletFramework.Core.Json; - -namespace WalletFramework.Oid4Vc.Oid4Vp.Models; - -/// -/// Used to persist OpenId4Vp presentations. -/// -[JsonConverter(typeof(OidPresentationRecordConverter))] -public sealed class OidPresentationRecord : RecordBase -{ - public const int CurrentVersion = 2; - - /// - /// Gets or sets the credentials the Holder presented to the Verifier. - /// - public List PresentedCredentialSets { get; set; } - - /// - /// Gets or sets the client id and identifies the Verifier. - /// - [JsonIgnore] - public string ClientId - { - get => Get(); - set => Set(value, false); - } - - /// - /// Gets or sets the type name. - /// - public override string TypeName => "AF.OidPresentationRecord"; - - /// - /// Gets or sets the metadata of the Verifier. - /// - public Option ClientMetadata { get; set; } - - /// - /// Gets or sets the name of the presentation. - /// - [JsonIgnore] - public Option Name - { - get => Get(); - set => value.Match( - name => - { - Set(name, false); - }, - () => { }); - } - -#pragma warning disable CS8618 - /// - /// Parameterless Default Constructor. - /// - public OidPresentationRecord() - { - } -#pragma warning restore CS8618 - - /// - /// Constructor for Serialization. - /// - /// The credential sets the Holder presented to the Verifier. - /// The client id for the Verifier. - /// The id of the record. - /// The metadata of the Verifier. - /// The name of the presentation. - public OidPresentationRecord( - List presentedCredentialSets, - string clientId, - string id, - Option clientMetadata, - Option name) - { - ClientId = clientId; - ClientMetadata = clientMetadata; - Id = id; - Name = name; - PresentedCredentialSets = presentedCredentialSets; - RecordVersion = CurrentVersion; - } -} - -public class OidPresentationRecordConverter : JsonConverter -{ - public override void WriteJson(JsonWriter writer, OidPresentationRecord? value, JsonSerializer serializer) - { - var json = value!.EncodeToJson(); - json.WriteTo(writer); - } - - public override OidPresentationRecord ReadJson( - JsonReader reader, - Type objectType, - OidPresentationRecord? existingValue, - bool hasExistingValue, - JsonSerializer serializer) - { - var json = JObject.Load(reader); - return OidPresentationRecordExtensions.DecodeFromJson(json); - } -} - -public static class OidPresentationRecordExtensions -{ - private const string PresentedCredentialSetsJsonKey = "presented_credential_sets"; - private const string ClientMetadataJsonKey = "client_metadata"; - private const string ClientIdJsonKey = "client_id"; - private const string NameJsonKey = "name"; - private const string RecordVersionJsonKey = "record_version"; - - public static JObject EncodeToJson(this OidPresentationRecord credentialSetRecord) - { - var result = new JObject(); - - result.Add(nameof(RecordBase.Id), credentialSetRecord.Id); - - result.Add(ClientIdJsonKey, credentialSetRecord.ClientId); - - var presentedCredentialSetArray = new JArray(); - foreach (var presentedCredentialSet in credentialSetRecord.PresentedCredentialSets) - { - presentedCredentialSetArray.Add(presentedCredentialSet.EncodeToJson()); - } - result.Add(PresentedCredentialSetsJsonKey, presentedCredentialSetArray); - - credentialSetRecord.ClientMetadata.IfSome(clientMetadata => result.Add(ClientMetadataJsonKey, JsonConvert.SerializeObject(clientMetadata))); - - credentialSetRecord.Name.IfSome(name => result.Add(NameJsonKey, name)); - - return result; - } - - public static OidPresentationRecord DecodeFromJson(JObject json) - { - var id = json[nameof(RecordBase.Id)]!.ToString(); - - var clientId = json[ClientIdJsonKey]!.ToString(); - - var presentedCredentialSets = - from jToken in json.GetByKey(PresentedCredentialSetsJsonKey).ToOption() - from jArray in jToken.ToJArray().ToOption() - from presentedCredentialSet in PresentedCredentialSetExtensions.DecodeFromJson(jArray) - select presentedCredentialSet; - - var clientMetadata = - from jToken in json.GetByKey(ClientMetadataJsonKey).ToOption() - select JsonConvert.DeserializeObject(jToken.ToString()); - - var name = - from jToken in json.GetByKey(NameJsonKey).ToOption() - select jToken.ToString(); - - return new OidPresentationRecord( - presentedCredentialSets.ToList(), - clientId, - id, - clientMetadata, - name); - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/PresentedCredential.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/PresentedCredential.cs deleted file mode 100644 index a89439ab..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/PresentedCredential.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace WalletFramework.Oid4Vc.Oid4Vp.Models; - -/// -/// Represents a presented credential. -/// -public class PresentedCredential -{ - /// - /// Gets or Sets the claims of the credential that were presented. - /// - public Dictionary PresentedClaims { get; set; } = null!; - - /// - /// Gets or Sets the credential id. - /// - public string CredentialId { get; set; } = null!; -} \ No newline at end of file diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/PresentedCredentialSet.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/PresentedCredentialSet.cs index fbc67ace..20991a1c 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/PresentedCredentialSet.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/PresentedCredentialSet.cs @@ -15,28 +15,32 @@ public record PresentedCredentialSet public Option SdJwtCredentialType { get; init; } - public Option MDocCredentialType { get; init; } + public Option MdocCredentialType { get; init; } public Dictionary PresentedClaims { get; init; } = null!; } public static class PresentedCredentialSetExtensions { - private const string CredentialSetIdJsonKey = "credential_set_id"; - private const string SdJwtCredentialTypeJsonKey = "sd_jwt_credential_type"; - private const string MDocCredentialTypeJsonKey = "mdoc_credential_type"; - private const string PresentedClaimsJsonKey = "presented_claims"; + private const string CredentialSetIdJsonKey = "CredentialSetId"; + private const string SdJwtCredentialTypeJsonKey = "SdJwtCredentialType"; + private const string MDocCredentialTypeJsonKey = "MdocCredentialType"; + private const string PresentedClaimsJsonKey = "PresentedClaims"; public static JObject EncodeToJson(this PresentedCredentialSet presentedCredentialSet) { - var result = new JObject(); - - result.Add(CredentialSetIdJsonKey, presentedCredentialSet.CredentialSetId.ToString()); + var result = new JObject + { + { + CredentialSetIdJsonKey, + presentedCredentialSet.CredentialSetId.ToString() + } + }; presentedCredentialSet.SdJwtCredentialType.IfSome(sdJwtType => result.Add(SdJwtCredentialTypeJsonKey, sdJwtType.ToString())); - presentedCredentialSet.MDocCredentialType.IfSome(mDocType => + presentedCredentialSet.MdocCredentialType.IfSome(mDocType => result.Add(MDocCredentialTypeJsonKey, mDocType.ToString())); var jObjectDictionary = new JObject(); @@ -82,7 +86,7 @@ from displays in claimsJson.Properties().Select(prop => ( { CredentialSetId = CredentialSetId .ValidCredentialSetId(credentialSetId).UnwrapOrThrow(), SdJwtCredentialType = sdJwtCredentialType, - MDocCredentialType = mDocCredentialType, + MdocCredentialType = mDocCredentialType, PresentedClaims = presentedClaims.ToDictionary(kvp => kvp.ClaimName, kvp => kvp.ClaimValue) }; } diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/SelectedCredential.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/SelectedCredential.cs index 731b53a5..ed6d2d14 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/SelectedCredential.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/SelectedCredential.cs @@ -20,9 +20,10 @@ public record SelectedCredential( public static class SelectedCredentialFun { /// - /// Returns the string representations of claims to disclose for the given credential and format. + /// Returns the string representations of claims to disclose for the given credential and format. /// - public static IReadOnlyList GetClaimsToDiscloseAsStrs(this SelectedCredential selectedCredential, CredentialQuery query) + public static IReadOnlyList GetClaimsToDiscloseAsStrs(this SelectedCredential selectedCredential, + CredentialQuery query) { return selectedCredential.ClaimsToDisclose.Match( claims => claims.AsStrings(query.Format), diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/WalletMetadata.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/WalletMetadata.cs index 09ecc5c7..98c0ce29 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/WalletMetadata.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/WalletMetadata.cs @@ -26,12 +26,12 @@ public static WalletMetadata CreateDefault() { SdJwtVcFormat = new SdJwtFormat { - IssuerSignedJwtAlgValues = ["ES256", "ES384", "ES512", "RS256"], + IssuerSignedJwtAlgValues = ["ES256"], KeyBindingJwtAlgValues = ["ES256"] }, SdJwtDcFormat = new SdJwtFormat { - IssuerSignedJwtAlgValues = ["ES256", "ES384", "ES512", "RS256"], + IssuerSignedJwtAlgValues = ["ES256"], KeyBindingJwtAlgValues = ["ES256"] }, MDocFormat = new MDocFormat diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/v1/OidPresentationRecord.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Models/v1/OidPresentationRecord.cs deleted file mode 100644 index 5c29bfd4..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Models/v1/OidPresentationRecord.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Hyperledger.Aries.Storage; -using Newtonsoft.Json; - -namespace WalletFramework.Oid4Vc.Oid4Vp.Models.v1; - -/// -/// Used to persist OpenId4Vp presentations. -/// -public sealed class OidPresentationRecord : RecordBase -{ - /// - /// Gets or sets the credentials the Holder presented to the Verifier. - /// - public PresentedCredential[] PresentedCredentials { get; set; } - - /// - /// Gets or sets the client id and identifies the Verifier. - /// - [JsonIgnore] - public string ClientId - { - get => Get(); - set => Set(value, false); - } - - /// - /// Gets or sets the type name. - /// - public override string TypeName => "AF.OidPresentationRecord"; - - /// - /// Gets or sets the metadata of the Verifier. - /// - public ClientMetadata? ClientMetadata { get; set; } - - /// - /// Gets or sets the name of the presentation. - /// - [JsonIgnore] - public string? Name - { - get => Get(); - set => Set(value!, false); - } - -#pragma warning disable CS8618 - /// - /// Parameterless Default Constructor. - /// - public OidPresentationRecord() - { - } -#pragma warning restore CS8618 - - /// - /// Constructor for Serialization. - /// - /// The credentials the Holder presented to the Verifier. - /// The client id for the Verifier. - /// The id of the record. - /// The metadata of the Verifier. - /// The name of the presentation. - [JsonConstructor] - private OidPresentationRecord( - PresentedCredential[] presentedCredentials, - string clientId, - string id, - ClientMetadata? clientMetadata, - string? name) - { - ClientId = clientId; - ClientMetadata = clientMetadata; - Id = id; - Name = name; - PresentedCredentials = presentedCredentials; - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRecord.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRecord.cs new file mode 100644 index 00000000..c6acb30e --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRecord.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; +using WalletFramework.Storage.Records; +using WalletFramework.Oid4Vc.Oid4Vp; + +namespace WalletFramework.Oid4Vc.Oid4Vp.Persistence; + +/// +/// Storage-only model for OpenID4VP presentations. +/// +public sealed record CompletedPresentationRecord : RecordBase +{ + public string PresentationId { get; init; } + + public string ClientId { get; init; } + + public string Serialized { get; init; } + +#pragma warning disable CS8618 + // ReSharper disable once UnusedMember.Local + // Used by EF + private CompletedPresentationRecord() : base(Guid.NewGuid()) + { + } +#pragma warning restore CS8618 + + public CompletedPresentationRecord(CompletedPresentation domain) : base(Guid.NewGuid()) + { + PresentationId = domain.PresentationId; + ClientId = domain.ClientId; + Serialized = domain.Serialize(); + } + + public CompletedPresentation ToDomainModel() + { + return CompletedPresentationExtensions.Deserialize(Serialized); + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRecordConfiguration.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRecordConfiguration.cs new file mode 100644 index 00000000..8393b9e1 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRecordConfiguration.cs @@ -0,0 +1,19 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Oid4Vc.Oid4Vp.Persistence; + +public sealed record CompletedPresentationRecordConfiguration : IRecordConfiguration +{ + public Unit Configure(ModelBuilder modelBuilder) + { + var entity = modelBuilder.Entity(); + entity.HasIndex(r => r.ClientId); + entity.HasIndex(r => r.PresentationId).IsUnique(); + entity.Property(r => r.PresentationId).IsRequired(); + entity.Property(r => r.ClientId).IsRequired(); + entity.Property(r => r.Serialized).IsRequired(); + return Unit.Default; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRepository.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRepository.cs new file mode 100644 index 00000000..80657df3 --- /dev/null +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Persistence/CompletedPresentationRepository.cs @@ -0,0 +1,98 @@ +using LanguageExt; +using Newtonsoft.Json; +using WalletFramework.Storage; +using WalletFramework.Storage.Repositories; + +namespace WalletFramework.Oid4Vc.Oid4Vp.Persistence; + +public class CompletedPresentationRepository(IRepository repository) + : IDomainRepository +{ + public async Task Add(CompletedPresentation domainModel) + { + await repository.Add(new CompletedPresentationRecord(domainModel)); + return Unit.Default; + } + + public async Task AddMany(IEnumerable domainModels) + { + var records = domainModels.Select(d => new CompletedPresentationRecord(d)); + await repository.AddMany(records); + return Unit.Default; + } + + public async Task Delete(string id) + { + var recs = await repository.Find(r => r.PresentationId == id); + await recs.Match( + Some: async list => + { + foreach (var record in list) + { + await repository.Remove(record); + } + }, + None: () => Task.CompletedTask); + + return Unit.Default; + } + + public async Task Delete(CompletedPresentation domainModel) + { + var recs = await repository.Find(r => r.PresentationId == domainModel.PresentationId); + await recs.Match( + Some: async list => + { + foreach (var record in list) + { + await repository.Remove(record); + } + }, + None: () => Task.CompletedTask); + + return Unit.Default; + } + + public async Task>> Find(ISearchConfig config) + { + var records = await repository.Find(config.ToPredicate()); + return from recs in records + let domains = recs.Select(r => r.ToDomainModel()) + select domains.ToList(); + } + + public async Task> GetById(string id) + { + var records = await repository.Find(r => r.PresentationId == id); + return from recs in records + let record = recs.FirstOrDefault() + select record?.ToDomainModel(); + } + + public async Task>> ListAll() + { + var records = await repository.ListAll(); + return from recs in records + let domains = recs.Select(r => r.ToDomainModel()) + select domains.ToList(); + } + + public async Task Update(CompletedPresentation domainModel) + { + var existingOpt = await repository.Find(r => r.ClientId == domainModel.ClientId); + + await existingOpt.Match( + Some: async list => + { + var existing = list[0]; + var updated = existing with { Serialized = domainModel.Serialize() }; + await repository.Update(updated); + }, + None: async () => + { + await repository.Add(new CompletedPresentationRecord(domainModel)); + }); + + return Unit.Default; + } +} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Services/PexService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Services/PexService.cs index 6b809e9b..0de88be0 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Services/PexService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Services/PexService.cs @@ -1,27 +1,27 @@ using System.IdentityModel.Tokens.Jwt; -using Hyperledger.Aries.Agents; using LanguageExt; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using WalletFramework.Core.Credentials.Abstractions; using WalletFramework.Core.Functional; using WalletFramework.MdocLib.Issuer; using WalletFramework.MdocLib.Security.Cose; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.Implementations; using WalletFramework.Oid4Vc.Oid4Vp.AuthResponse; using WalletFramework.Oid4Vc.Oid4Vp.Models; using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models; using WalletFramework.Oid4Vc.Oid4Vp.Query; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; +using WalletFramework.MdocVc.Persistence; +using WalletFramework.Storage; +using WalletFramework.Core.Credentials; +using WalletFramework.MdocVc; +using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Persistence; namespace WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Services; /// public class PexService( - IAgentProvider agentProvider, - IMdocStorage mdocStorage, - ISdJwtVcHolderService sdJwtVcHolderService) : IPexService + IDomainRepository mdocRepository, + IDomainRepository sdJwtRepository) : IPexService { public async Task FindPresentationCandidatesAsync(PresentationDefinition presentationDefinition, Option supportedFormatSigningAlgorithms) { @@ -142,24 +142,22 @@ private async Task>> GetMatchingCredentials( InputDescriptor inputDescriptor, Option supportedFormatSigningAlgorithms) { - var context = await agentProvider.GetContextAsync(); + var sdJwtRecords = await sdJwtRepository.ListAll(); + var mdocRecords = await mdocRepository.ListAll(); - var sdJwtRecords = await sdJwtVcHolderService.ListAsync(context); - var mdocRecords = await mdocStorage.ListAll(); - - var filteredSdJwtRecords = sdJwtRecords.Where(record => + var filteredSdJwtRecords = sdJwtRecords.OnSome(credentials => credentials.Where(sdJwtCredential => { - var doc = record.ToSdJwtDoc(); + var doc = sdJwtCredential.SdJwtDoc; var handler = new JwtSecurityTokenHandler(); var issuerSignedJwt = handler.ReadJwtToken(doc.IssuerSignedJwt); return issuerSignedJwt.Header.TryGetValue("alg", out var alg) && supportedFormatSigningAlgorithms.Match( - formats => (formats.SdJwtVcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString()) ?? true) - || (formats.SdJwtDcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString()) ?? true), - () => (inputDescriptor.Formats?.SdJwtVcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString()) ?? true) - || (inputDescriptor.Formats?.SdJwtDcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString()) ?? true)) + formats => (formats.SdJwtVcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString() ?? string.Empty) ?? true) + || (formats.SdJwtDcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString() ?? string.Empty) ?? true), + () => (inputDescriptor.Formats?.SdJwtVcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString() ?? string.Empty) ?? true) + || (inputDescriptor.Formats?.SdJwtDcFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString() ?? string.Empty) ?? true)) && inputDescriptor.Constraints.Fields!.All(field => { try @@ -178,12 +176,12 @@ private async Task>> GetMatchingCredentials( return false; } }); - }).Cast().AsOption(); + }).Cast()); var filteredMdocRecords = mdocRecords.OnSome(records => records .Where(record => { - return record.DocType == inputDescriptor.Id + return record.Mdoc.DocType == inputDescriptor.Id && record.Mdoc.IssuerSigned.IssuerAuth.ProtectedHeaders.Value.TryGetValue(new CoseLabel(1), out var alg) && inputDescriptor.Constraints.Fields!.All(field => { diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/AuthorizationRequestService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/AuthorizationRequestService.cs index 110649bd..b6857d66 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/AuthorizationRequestService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/AuthorizationRequestService.cs @@ -1,6 +1,7 @@ using System.Net.Http.Headers; using System.Web; using LanguageExt; +using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using WalletFramework.Core.Functional; diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/ICandidateQueryService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/ICandidateQueryService.cs index e7373976..fdacf93d 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/ICandidateQueryService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/ICandidateQueryService.cs @@ -1,6 +1,5 @@ using LanguageExt; using OneOf; -using WalletFramework.Oid4Vc.Oid4Vp.DcApi.Models; using WalletFramework.Oid4Vc.Oid4Vp.Dcql.CredentialQueries; using WalletFramework.Oid4Vc.Oid4Vp.Models; using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models; diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/IOid4VpRecordService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/IOid4VpRecordService.cs deleted file mode 100644 index 1ca04a73..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/IOid4VpRecordService.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; -using WalletFramework.Oid4Vc.Oid4Vp.Models; - -namespace WalletFramework.Oid4Vc.Oid4Vp.Services; - -/// -/// This Service offers methods to interact the OpenId4Vp protocol -/// -public interface IOid4VpRecordService -{ - /// - /// Retrieves a specific OidPresentation record by its ID. - /// - /// The agent context. - /// The ID of the OidPresentation record to retrieve. - /// - /// A task representing the asynchronous operation. The task result contains the - /// associated with the given ID. - /// - Task GetAsync(IAgentContext context, string presentationId); - - /// - /// Lists OidPresentation records based on specified criteria. - /// - /// The agent context. - /// The search query to filter OidPresentation records. Default is null, meaning no filter. - /// The maximum number of records to retrieve. Default is 100. - /// The number of records to skip. Default is 0. - /// - /// A task representing the asynchronous operation. The task result contains a list of - /// that match the criteria. - /// - Task> ListAsync(IAgentContext context, ISearchQuery? query = null, int count = 100, - int skip = 0); - - /// - /// Stores a new OidPresentation record. - /// - /// The agent context. - /// The presentation record. - /// A task representing the asynchronous operation. The task result contains the ID of the stored OidPresentation record. - Task StoreAsync(IAgentContext context, OidPresentationRecord oidPresentationRecord); - - /// - /// Deletes a specific OidPresentation record by its ID. - /// - /// The agent context. - /// The ID of the OidPresentation record to delete. - /// - /// A task representing the asynchronous operation. The task result indicates whether the deletion was successful. - /// - Task DeleteAsync(IAgentContext context, string recordId); -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpClientService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpClientService.cs index fdbc542c..69c2e050 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpClientService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpClientService.cs @@ -1,8 +1,6 @@ using System.Net.Mime; using System.Security.Cryptography; using System.Text; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Extensions; using LanguageExt; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; @@ -11,6 +9,7 @@ using WalletFramework.Core.Credentials; using WalletFramework.Core.Credentials.Abstractions; using WalletFramework.Core.Functional; +using WalletFramework.Core.String; using WalletFramework.MdocLib; using WalletFramework.MdocLib.Device; using WalletFramework.MdocLib.Device.Response; @@ -18,10 +17,11 @@ using WalletFramework.MdocLib.Security; using WalletFramework.MdocLib.Security.Cose; using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; using WalletFramework.Oid4Vc.ClientAttestation; using WalletFramework.Oid4Vc.Errors; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Abstractions; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models; using WalletFramework.Oid4Vc.Oid4Vci.Extensions; @@ -30,13 +30,16 @@ using WalletFramework.Oid4Vc.Oid4Vp.Dcql.CredentialQueries; using WalletFramework.Oid4Vc.Oid4Vp.Errors; using WalletFramework.Oid4Vc.Oid4Vp.Models; +using WalletFramework.Oid4Vc.Oid4Vp.Persistence; using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models; using WalletFramework.Oid4Vc.Oid4Vp.TransactionDatas; using WalletFramework.Oid4Vc.Qes.Authorization; using WalletFramework.SdJwtLib.Models; +using WalletFramework.SdJwtVc; using WalletFramework.SdJwtVc.Models; -using WalletFramework.SdJwtVc.Models.Records; +using WalletFramework.SdJwtVc.Persistence; using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; +using WalletFramework.Storage; using static Newtonsoft.Json.JsonConvert; using static WalletFramework.MdocLib.Security.Cose.ProtectedHeaders; using Format = WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.Format; @@ -49,7 +52,6 @@ public class Oid4VpClientService : IOid4VpClientService /// /// Initializes a new instance of the class. /// - /// The agent provider /// The Auth Flow Session Storage. /// The authorization request service. /// The authorization response encryption service. @@ -57,28 +59,28 @@ public class Oid4VpClientService : IOid4VpClientService /// The client attestation service. /// The http client factory to create http clients. /// The ILogger. - /// The service responsible for mDOc storage operations. + /// The service responsible for mdoc storage operations. + /// The service responsible for SD-JWT storage operations. /// The service responsible for OpenId4VP related operations. - /// The service responsible for OidPresentationRecord related operations. + /// The service responsible for OidPresentationRecord related operations. /// The authorization response service. /// The service responsible for SD-JWT related operations. public Oid4VpClientService( - IAgentProvider agentProvider, - IAuthFlowSessionStorage authFlowSessionStorage, + IDomainRepository authFlowSessionStorage, IAuthorizationRequestService authorizationRequestService, IAuthorizationResponseEncryptionService authorizationResponseEncryptionService, ICandidateQueryService candidateQueryService, IClientAttestationService clientAttestationService, IHttpClientFactory httpClientFactory, ILogger logger, - IMdocStorage mDocStorage, + IDomainRepository mdocRepository, + IDomainRepository sdJwtRepository, + IDomainRepository presentationRepository, IOid4VpHaipClient oid4VpHaipClient, - IOid4VpRecordService oid4VpRecordService, IPresentationService presentationService, IVerifierKeyService verifierKeyService, ISdJwtVcHolderService sdJwtVcHolderService) { - _agentProvider = agentProvider; _authFlowSessionStorage = authFlowSessionStorage; _authorizationRequestService = authorizationRequestService; _authorizationResponseEncryptionService = authorizationResponseEncryptionService; @@ -86,25 +88,26 @@ public Oid4VpClientService( _clientAttestationService = clientAttestationService; _httpClientFactory = httpClientFactory; _logger = logger; - _mDocStorage = mDocStorage; + _mdocRepository = mdocRepository; + _sdJwtRepository = sdJwtRepository; _oid4VpHaipClient = oid4VpHaipClient; - _oid4VpRecordService = oid4VpRecordService; + _presentationRepository = presentationRepository; _presentationService = presentationService; _verifierKeyService = verifierKeyService; _sdJwtVcHolderService = sdJwtVcHolderService; } - private readonly IAgentProvider _agentProvider; - private readonly IAuthFlowSessionStorage _authFlowSessionStorage; + private readonly IDomainRepository _authFlowSessionStorage; private readonly IAuthorizationRequestService _authorizationRequestService; private readonly IAuthorizationResponseEncryptionService _authorizationResponseEncryptionService; private readonly ICandidateQueryService _candidateQueryService; private readonly IClientAttestationService _clientAttestationService; private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; - private readonly IMdocStorage _mDocStorage; + private readonly IDomainRepository _mdocRepository; + private readonly IDomainRepository _sdJwtRepository; + private readonly IDomainRepository _presentationRepository; private readonly IOid4VpHaipClient _oid4VpHaipClient; - private readonly IOid4VpRecordService _oid4VpRecordService; private readonly IPresentationService _presentationService; private readonly IVerifierKeyService _verifierKeyService; private readonly ISdJwtVcHolderService _sdJwtVcHolderService; @@ -183,28 +186,27 @@ await clientAttestationDetails.IfSomeAsync(async details => }); // ToDo: when to delete these records? - var context = await _agentProvider.GetContextAsync(); foreach (var credential in credentials) { switch (credential.Credential) { - case SdJwtRecord { OneTimeUse: true } sdJwtRecord: - var credentialSetSdJwtRecords = await _sdJwtVcHolderService.ListAsync(context, sdJwtRecord.GetCredentialSetId()); + case SdJwtCredential { OneTimeUse: true } sdJwtRecord: + var credentialSetSdJwtRecords = await _sdJwtRepository.ListAll(); await credentialSetSdJwtRecords.Match( async sdJwtRecords => { if (sdJwtRecords.Count() > 1) - await _sdJwtVcHolderService.DeleteAsync(context, sdJwtRecord.GetId()); + await _sdJwtRepository.Delete(sdJwtRecord.GetId()); }, () => Task.CompletedTask); break; - case MdocRecord { OneTimeUse: true } mDocRecord: - var credentialSetMdocRecords = await _mDocStorage.List(mDocRecord.GetCredentialSetId()); + case MdocCredential { OneTimeUse: true } mDocRecord: + var credentialSetMdocRecords = await _mdocRepository.ListAll(); await credentialSetMdocRecords.Match( async mDocRecords => { if (mDocRecords.Count() > 1) - await _mDocStorage.Delete(mDocRecord); + await _mdocRepository.Delete(mDocRecord.GetId()); }, () => Task.CompletedTask); break; @@ -224,7 +226,7 @@ await credentialSetMdocRecords.Match( switch (presentation.PresentedCredential) { - case SdJwtRecord sdJwtRecord: + case SdJwtCredential sdJwtRecord: var issuanceSdJwtDoc = sdJwtRecord.ToSdJwtDoc(); var sdJwtDoc = new SdJwtDoc(presentation.PresentationMap.Presentation); @@ -251,13 +253,13 @@ from claim in sdJwtRecord.Claims PresentedClaims = presentedClaims.ToDictionary(itm => itm.key, itm => itm.value) }; break; - case MdocRecord mdocRecord: - var claims = mdocRecord.Mdoc.IssuerSigned.IssuerNameSpaces.Value.SelectMany(pair => pair.Value); + case MdocCredential mdocCredential: + var claims = mdocCredential.Mdoc.IssuerSigned.IssuerNameSpaces.Value.SelectMany(pair => pair.Value); result = new PresentedCredentialSet { - MDocCredentialType = mdocRecord.DocType, - CredentialSetId = mdocRecord.GetCredentialSetId(), + MdocCredentialType = mdocCredential.Mdoc.DocType, + CredentialSetId = mdocCredential.GetCredentialSetId(), PresentedClaims = claims.ToDictionary( item => item.ElementId.ToString(), item => new PresentedClaim { Value = item.Element.ToString() } @@ -271,18 +273,17 @@ from claim in sdJwtRecord.Claims return result; }); - var oidPresentationRecord = new OidPresentationRecord - { - Id = Guid.NewGuid().ToString(), - ClientId = authorizationRequest.ClientId!, - ClientMetadata = authorizationRequest.ClientMetadata, - Name = authorizationRequest.Requirements.Match( + var oidPresentationRecord = new CompletedPresentation( + Guid.NewGuid().ToString(), + authorizationRequest.ClientId!, + presentedCredentials.ToList(), + authorizationRequest.ClientMetadata, + authorizationRequest.Requirements.Match( _ => Option.None, presentationDefinition => presentationDefinition.Name), - PresentedCredentialSets = presentedCredentials.ToList() - }; + DateTime.UtcNow); - await _oid4VpRecordService.StoreAsync(context, oidPresentationRecord); + await _presentationRepository.Add(oidPresentationRecord); var redirectUriJson = await responseMessage.Content.ReadAsStringAsync(); @@ -311,8 +312,6 @@ public async Task> AcceptOnDemandRequest( var mdocNonce = Option.None; - var context = await _agentProvider.GetContextAsync(); - var presentations = new List<(PresentationMap PresentationMap, ICredential PresentedCredential)>(); foreach (var credential in credentials) { @@ -336,7 +335,8 @@ public async Task> AcceptOnDemandRequest( Format format; ICredential presentedCredential; - var session = await _authFlowSessionStorage.GetAsync(context, issuanceSession.AuthFlowSessionState); + var session = (await _authFlowSessionStorage.GetById(issuanceSession.AuthFlowSessionState)) + .UnwrapOrThrow(new InvalidOperationException("Auth flow session not found")); var client = _httpClientFactory.CreateClient(); client.WithAuthorizationHeader(session.AuthorizationData.OAuthToken.UnwrapOrThrow(new Exception())); @@ -346,7 +346,7 @@ public async Task> AcceptOnDemandRequest( var presentation = string.Empty; switch (credential.Credential) { - case SdJwtRecord sdJwt: + case SdJwtCredential sdJwt: format = Format.ValidFormat(sdJwt.Format).UnwrapOrThrow(); presentation = await _sdJwtVcHolderService.CreatePresentation( @@ -361,7 +361,7 @@ public async Task> AcceptOnDemandRequest( var kbJwt = presentation[presentation.LastIndexOf('~')..][1..]; var kbJwtWithoutSignature = kbJwt[..kbJwt.LastIndexOf('.')]; - var kbJwtWithoutSignatureHash = sha256.ComputeHash(kbJwtWithoutSignature.GetUTF8Bytes()); + var kbJwtWithoutSignatureHash = sha256.ComputeHash(kbJwtWithoutSignature.GetUtf8Bytes()); var sdJwtContent = new JObject { @@ -391,7 +391,7 @@ public async Task> AcceptOnDemandRequest( presentedCredential = sdJwt; break; - case MdocRecord mdocRecord: + case MdocCredential mdocCredential: format = FormatFun.CreateMdocFormat(); var toDisclose = claims.Select(claim => @@ -409,7 +409,7 @@ public async Task> AcceptOnDemandRequest( .GroupBy(nameSpaceAndElementId => nameSpaceAndElementId.NameSpace, tuple => tuple.ElementId) .ToDictionary(group => group.Key, group => group.ToList()); - var mdoc = mdocRecord.Mdoc.SelectivelyDisclose(toDisclose); + var mdoc = mdocCredential.Mdoc.SelectivelyDisclose(toDisclose); var responseEncryptionKey = authorizationRequest.ResponseMode == AuthorizationRequest.DirectPostJwt ? await _verifierKeyService.GetPublicKey(authorizationRequest) @@ -469,7 +469,7 @@ from keyAuths in mdoc.IssuerSigned.IssuerAuth.Payload.DeviceKeyInfo.KeyAuthoriza .EncodeToBase64Url(); } - presentedCredential = mdocRecord; + presentedCredential = mdocCredential; break; default: @@ -515,7 +515,7 @@ from keyAuths in mdoc.IssuerSigned.IssuerAuth.Payload.DeviceKeyInfo.KeyAuthoriza switch (presentation.PresentedCredential) { - case SdJwtRecord sdJwtRecord: + case SdJwtCredential sdJwtRecord: var issuanceSdJwtDoc = sdJwtRecord.ToSdJwtDoc(); var sdJwtDoc = new SdJwtDoc(presentation.PresentationMap.Presentation); @@ -542,13 +542,13 @@ from claim in sdJwtRecord.Claims PresentedClaims = presentedClaims.ToDictionary(itm => itm.key, itm => itm.value) }; break; - case MdocRecord mdocRecord: - var claims = mdocRecord.Mdoc.IssuerSigned.IssuerNameSpaces.Value.SelectMany(pair => pair.Value); + case MdocCredential mdocCredential: + var claims = mdocCredential.Mdoc.IssuerSigned.IssuerNameSpaces.Value.SelectMany(pair => pair.Value); result = new PresentedCredentialSet { - MDocCredentialType = mdocRecord.DocType, - CredentialSetId = mdocRecord.GetCredentialSetId(), + MdocCredentialType = mdocCredential.Mdoc.DocType, + CredentialSetId = mdocCredential.GetCredentialSetId(), PresentedClaims = claims.ToDictionary( item => item.ElementId.ToString(), item => new PresentedClaim { Value = item.Element.ToString() } @@ -562,19 +562,18 @@ from claim in sdJwtRecord.Claims return result; }); - var oidPresentationRecord = new OidPresentationRecord - { - Id = Guid.NewGuid().ToString(), - ClientId = authorizationRequest.ClientId!, - ClientMetadata = authorizationRequest.ClientMetadata, - Name = authorizationRequest.Requirements.Match( + var oidPresentationRecord = new CompletedPresentation( + Guid.NewGuid().ToString(), + authorizationRequest.ClientId!, + presentedCredentials.ToList(), + authorizationRequest.ClientMetadata, + authorizationRequest.Requirements.Match( _ => Option.None, presentationDefinition => presentationDefinition.Name), - PresentedCredentialSets = presentedCredentials.ToList() - }; - - await _oid4VpRecordService.StoreAsync(context, oidPresentationRecord); + DateTime.UtcNow); + await _presentationRepository.Add(oidPresentationRecord); + var redirectUriJson = await responseMessage.Content.ReadAsStringAsync(); try diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpRecordService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpRecordService.cs deleted file mode 100644 index f1fe99d2..00000000 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpRecordService.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Hyperledger.Aries; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; -using WalletFramework.Oid4Vc.Oid4Vp.Models; - -namespace WalletFramework.Oid4Vc.Oid4Vp.Services; - -/// -public class Oid4VpRecordService : IOid4VpRecordService -{ - /// - /// The service responsible for wallet record operations. - /// - protected readonly IWalletRecordService RecordService; - - /// - /// Initializes a new instance of the class. - /// - /// The service responsible for wallet record operations. - public Oid4VpRecordService(IWalletRecordService recordService) - { - RecordService = recordService; - } - - /// - public async Task GetAsync(IAgentContext context, string presentationId) - { - var record = await RecordService.GetAsync(context.Wallet, presentationId); - if (record == null) - throw new AriesFrameworkException(ErrorCode.RecordNotFound, "OidPresentation record not found"); - - return record; - } - - /// - public Task> ListAsync(IAgentContext context, ISearchQuery? query = null, int count = 100, int skip = 0) - { - return RecordService.SearchAsync(context.Wallet, query, null, count, skip); - } - - /// - public async Task StoreAsync(IAgentContext context, OidPresentationRecord oidPresentationRecord) - { - await RecordService.AddAsync(context.Wallet, oidPresentationRecord); - - return oidPresentationRecord.Id; - } - - /// - public Task DeleteAsync(IAgentContext context, string recordId) - { - return RecordService.DeleteAsync(context.Wallet, recordId); - } -} diff --git a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/PresentationService.cs b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/PresentationService.cs index e0eaea13..ef0639b4 100644 --- a/src/WalletFramework.Oid4Vc/Oid4Vp/Services/PresentationService.cs +++ b/src/WalletFramework.Oid4Vc/Oid4Vp/Services/PresentationService.cs @@ -1,6 +1,7 @@ using LanguageExt; using Microsoft.IdentityModel.Tokens; using OneOf; +using WalletFramework.Core.Credentials; using WalletFramework.Core.Credentials.Abstractions; using WalletFramework.Core.Functional; using WalletFramework.MdocLib; @@ -16,8 +17,10 @@ using WalletFramework.Oid4Vc.Oid4Vp.Models; using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models; using WalletFramework.Oid4Vc.Oid4Vp.TransactionDatas; -using WalletFramework.SdJwtVc.Models.Records; +using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Persistence; using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; +using WalletFramework.Storage; namespace WalletFramework.Oid4Vc.Oid4Vp.Services; @@ -30,19 +33,23 @@ public class PresentationService : IPresentationService /// The service responsible for SD-JWT related operations. /// The mdoc authentication service. /// The verifier key service. + /// The service responsible for SD-JWT storage operations. public PresentationService( ISdJwtVcHolderService sdJwtVcHolderService, IMdocAuthenticationService mdocAuthenticationService, - IVerifierKeyService verifierKeyService) + IVerifierKeyService verifierKeyService, + IDomainRepository sdJwtRepository) { _sdJwtVcHolderService = sdJwtVcHolderService; _mdocAuthenticationService = mdocAuthenticationService; _verifierKeyService = verifierKeyService; + _sdJwtRepository = sdJwtRepository; } private readonly ISdJwtVcHolderService _sdJwtVcHolderService; private readonly IMdocAuthenticationService _mdocAuthenticationService; private readonly IVerifierKeyService _verifierKeyService; + private readonly IDomainRepository _sdJwtRepository; /// public async Task<(List<(PresentationMap PresentationMap, ICredential PresentedCredential)> Presentations, Option MdocNonce)> CreatePresentations( @@ -98,28 +105,20 @@ public PresentationService( Format format; ICredential presentedCredential; - string audience; - switch (authorizationRequest.ResponseMode) + var audience = authorizationRequest.ResponseMode switch { - case AuthorizationRequest.DcApi: - case AuthorizationRequest.DcApiJwt: - audience = origin.Match( - aud => $"origin:{aud}", - () => "origin:" + authorizationRequest.ClientId - ); - break; - case AuthorizationRequest.DirectPost: - case AuthorizationRequest.DirectPostJwt: - audience = authorizationRequest.ClientIdScheme?.AsString() + ":" + authorizationRequest.ClientId; - break; - default: - throw new ArgumentOutOfRangeException(nameof(authorizationRequest.ResponseMode)); - } + AuthorizationRequest.DcApi or AuthorizationRequest.DcApiJwt => origin.Match( + aud => $"origin:{aud}", + () => "origin:" + authorizationRequest.ClientId), + AuthorizationRequest.DirectPost or AuthorizationRequest.DirectPostJwt => authorizationRequest + .ClientIdScheme?.AsString() + ":" + authorizationRequest.ClientId, + _ => throw new ArgumentOutOfRangeException(nameof(authorizationRequest.ResponseMode)) + }; string presentation; switch (credential.Credential) { - case SdJwtRecord sdJwt: + case SdJwtCredential sdJwt: format = Format.ValidFormat(sdJwt.Format).UnwrapOrThrow(); presentation = await _sdJwtVcHolderService.CreatePresentation( @@ -133,7 +132,7 @@ public PresentationService( presentedCredential = sdJwt; break; - case MdocRecord mdocRecord: + case MdocCredential mdocCredential: format = FormatFun.CreateMdocFormat(); var toDisclose = claims.Select(claim => @@ -151,8 +150,7 @@ public PresentationService( .GroupBy(nameSpaceAndElementId => nameSpaceAndElementId.NameSpace, tuple => tuple.ElementId) .ToDictionary(group => group.Key, group => group.ToList()); - var mdoc = mdocRecord.Mdoc.SelectivelyDisclose(toDisclose); - + var mdoc = mdocCredential.Mdoc.SelectivelyDisclose(toDisclose); SessionTranscript sessionTranscript; switch (authorizationRequest.ResponseMode) @@ -162,7 +160,7 @@ public PresentationService( authorizationRequest, origin.UnwrapOrThrow(), Option.None); - + sessionTranscript = unencryptedVpDcApiHandover.ToSessionTranscript(); break; case AuthorizationRequest.DcApiJwt: @@ -170,7 +168,7 @@ public PresentationService( authorizationRequest, origin.UnwrapOrThrow(), await _verifierKeyService.GetPublicKey(authorizationRequest)); - + sessionTranscript = encryptedVpDcApiHandover.ToSessionTranscript(); mdocNonce = encryptedVpDcApiHandover.MdocGeneratedNonce; break; @@ -194,11 +192,11 @@ public PresentationService( } var authenticatedMdoc = await _mdocAuthenticationService.Authenticate( - mdoc, sessionTranscript, mdocRecord.KeyId); + mdoc, sessionTranscript, mdocCredential.KeyId); presentation = new Document(authenticatedMdoc).BuildDeviceResponse().EncodeToBase64Url(); - presentedCredential = mdocRecord; + presentedCredential = mdocCredential; break; default: throw new ArgumentOutOfRangeException(nameof(credential.Credential)); diff --git a/src/WalletFramework.Oid4Vc/RelyingPartyAuthentication/Implementations/RpAuthService.cs b/src/WalletFramework.Oid4Vc/RelyingPartyAuthentication/Implementations/RpAuthService.cs index aae19be9..3f3af5aa 100644 --- a/src/WalletFramework.Oid4Vc/RelyingPartyAuthentication/Implementations/RpAuthService.cs +++ b/src/WalletFramework.Oid4Vc/RelyingPartyAuthentication/Implementations/RpAuthService.cs @@ -3,7 +3,7 @@ namespace WalletFramework.Oid4Vc.RelyingPartyAuthentication.Implementations; -public class RpAuthService(Abstractions.IRpRegistrarService irpRegistrarService) : IRpAuthService +public class RpAuthService(IRpRegistrarService irpRegistrarService) : IRpAuthService { public async Task Authenticate(RequestObject requestObject) { diff --git a/src/WalletFramework.Oid4Vc/WalletFramework.Oid4Vc.csproj b/src/WalletFramework.Oid4Vc/WalletFramework.Oid4Vc.csproj index ca935e78..e74cd879 100644 --- a/src/WalletFramework.Oid4Vc/WalletFramework.Oid4Vc.csproj +++ b/src/WalletFramework.Oid4Vc/WalletFramework.Oid4Vc.csproj @@ -15,7 +15,6 @@ - diff --git a/src/WalletFramework.SdJwtLib/WalletFramework.SdJwtLib.csproj b/src/WalletFramework.SdJwtLib/WalletFramework.SdJwtLib.csproj index d839c784..923aa4e4 100644 --- a/src/WalletFramework.SdJwtLib/WalletFramework.SdJwtLib.csproj +++ b/src/WalletFramework.SdJwtLib/WalletFramework.SdJwtLib.csproj @@ -5,7 +5,7 @@ enable enable - + diff --git a/src/WalletFramework.SdJwtVc/Models/Credential/Attributes/ClaimDisplay.cs b/src/WalletFramework.SdJwtVc/Models/Credential/Attributes/ClaimDisplay.cs deleted file mode 100644 index 6c1a9d03..00000000 --- a/src/WalletFramework.SdJwtVc/Models/Credential/Attributes/ClaimDisplay.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace WalletFramework.SdJwtVc.Models.Credential.Attributes -{ - /// - /// Represents the visual representations for the credential attribute. - /// - public class ClaimDisplay - { - /// - /// Gets or sets the name for the credential attribute. - /// - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string? Name { get; set; } - - /// - /// Gets or sets the locale, which represents the specific culture or region. - /// - [JsonProperty("locale", NullValueHandling = NullValueHandling.Ignore)] - public string? Locale { get; set; } - } -} diff --git a/src/WalletFramework.SdJwtVc/Models/Credential/Attributes/ClaimMetadata.cs b/src/WalletFramework.SdJwtVc/Models/Credential/Attributes/ClaimMetadata.cs deleted file mode 100644 index e939d508..00000000 --- a/src/WalletFramework.SdJwtVc/Models/Credential/Attributes/ClaimMetadata.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace WalletFramework.SdJwtVc.Models.Credential.Attributes; - -/// -/// Represents the specifics about a claim. -/// -public class ClaimMetadata { - - [JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)] - public List? Path { get; set; } - - /// - /// Gets or sets the list of display properties associated with a specific credential attribute. - /// - /// - /// The list of display properties. Each display property provides information on how the credential attribute should - /// be displayed. - /// - [JsonProperty("display", NullValueHandling = NullValueHandling.Ignore)] - public List? Display { get; set; } - - /// - /// String value determining type of value of the claim. A non-exhaustive list of valid values defined by this - /// specification are string, number, and image media types such as image/jpeg. - /// - [JsonProperty("value_type", NullValueHandling = NullValueHandling.Ignore)] - public string? ValueType { get; set; } - - /// - /// String value determining type of value of the claim. A non-exhaustive list of valid values defined by this - /// specification are string, number, and image media types such as image/jpeg. - /// - [JsonProperty("mandatory", NullValueHandling = NullValueHandling.Ignore)] - public string? Mandatory { get; set; } - - [JsonProperty("nested_claims", NullValueHandling = NullValueHandling.Ignore)] - [JsonExtensionData] - public Dictionary? NestedClaims { get; set; } -} - diff --git a/src/WalletFramework.SdJwtVc/Models/Credential/CredentialDefinition.cs b/src/WalletFramework.SdJwtVc/Models/Credential/CredentialDefinition.cs deleted file mode 100644 index 6e688244..00000000 --- a/src/WalletFramework.SdJwtVc/Models/Credential/CredentialDefinition.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; - -namespace WalletFramework.SdJwtVc.Models.Credential -{ - /// - /// Represents the detailed description of the credential type. - /// - public class CredentialDefinition - { - /// - /// Gets or sets the verifiable credential type (vct). - /// - [JsonProperty("vct")] - public string Vct { get; set; } = null!; - - /// - /// Gets or sets the dictionary representing the attributes of the credential in different languages. - /// - [JsonProperty("claims")] - public Dictionary? Claims { get; set; } - } -} diff --git a/src/WalletFramework.SdJwtVc/Models/Credential/SdJwtDisplay.cs b/src/WalletFramework.SdJwtVc/Models/Credential/SdJwtDisplay.cs deleted file mode 100644 index 03248476..00000000 --- a/src/WalletFramework.SdJwtVc/Models/Credential/SdJwtDisplay.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Newtonsoft.Json; - -namespace WalletFramework.SdJwtVc.Models.Credential; - -/// -/// Represents the visual representations for the credential. -/// -public record SdJwtDisplay -{ - /// - /// Gets or sets the logo associated with this Credential. - /// - [JsonProperty("logo", NullValueHandling = NullValueHandling.Ignore)] - public SdJwtLogo? Logo { get; set; } - - /// - /// Gets or sets the name of the Credential. - /// - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string? Name { get; set; } - - /// - /// Gets or sets the background color for the Credential. - /// - [JsonProperty("background_color", NullValueHandling = NullValueHandling.Ignore)] - public string? BackgroundColor { get; set; } - - /// - /// Gets or sets the locale, which represents the specific culture or region. - /// - [JsonProperty("locale", NullValueHandling = NullValueHandling.Ignore)] - public string? Locale { get; set; } - - /// - /// Gets or sets the text color for the Credential. - /// - [JsonProperty("text_color", NullValueHandling = NullValueHandling.Ignore)] - public string? TextColor { get; set; } - - /// - /// Represents the Logo for a Credential. - /// - public class SdJwtLogo - { - /// - /// Gets or sets the alternate text that describes the logo image. This is typically used for accessibility purposes. - /// - [JsonProperty("alt_text")] - public string? AltText { get; set; } - - /// - /// Gets or sets the URL of the logo image. - /// - [JsonProperty("uri")] - public Uri Uri { get; set; } = null!; - } -} diff --git a/src/WalletFramework.SdJwtVc/Models/Credential/SdJwtMetadata.cs b/src/WalletFramework.SdJwtVc/Models/Credential/SdJwtMetadata.cs deleted file mode 100644 index 1f1c0f15..00000000 --- a/src/WalletFramework.SdJwtVc/Models/Credential/SdJwtMetadata.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Newtonsoft.Json; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; - -namespace WalletFramework.SdJwtVc.Models.Credential -{ - /// - /// Represents the metadata of a specific type of credential that a Credential Issuer can issue. - /// - public class SdJwtMetadata - { - /// - /// Gets or sets the verifiable credential type (vct). This is SD-JWT specific. - /// - [JsonProperty("vct")] - public string? Vct { get; set; } - - /// - /// - /// - [JsonProperty("scope")] - public string? Scope { get; set; } - - /// - /// Gets or sets the dictionary representing the attributes of the credential in different languages. - /// - [JsonProperty("claims")] - public Dictionary? Claims { get; set; } - - /// - /// Gets or sets a list of display properties of the supported credential for different languages. - /// - [JsonProperty("display", NullValueHandling = NullValueHandling.Ignore)] - public List? Display { get; set; } - - /// - /// Gets or sets a list of methods that identify how the Credential is bound to the identifier of the End-User who - /// possesses the Credential. - /// - [JsonProperty("cryptographic_binding_methods_supported", NullValueHandling = NullValueHandling.Ignore)] - public List? CryptographicBindingMethodsSupported { get; set; } - - /// - /// Gets or sets a list of identifiers for the signing algorithms that are supported by the issuer and used - /// to sign credentials. - /// - [JsonProperty("credential_signing_alg_values_supported", NullValueHandling = NullValueHandling.Ignore)] - public List? CredentialSigningAlgValuesSupported { get; set; } - - /// - /// A list of claim display names, arranged in the order in which they should be displayed by the Wallet. - /// - [JsonProperty("order", NullValueHandling = NullValueHandling.Ignore)] - public List? Order { get; set; } - - /// - /// Gets or sets the identifier for the format of the credential. - /// - [JsonProperty("format")] - public string Format { get; set; } = null!; - - /// - /// Gets or sets the unique identifier for the respective credential. - /// - [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] - public string? Id { get; set; } - - /// - /// Gets or sets a dictionary which maps a credential type to its supported signing algorithms for key proofs. - /// - [JsonProperty("proof_types_supported", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary? ProofTypesSupported { get; set; } - } - - /// - /// Represents credential type specific signing algorithm information. - /// - public class CredentialProofType - { - /// - /// Gets or sets the available signing algorithms for the associated credential type. - /// - [JsonProperty("proof_signing_alg_values_supported")] - public string[] ProofSigningAlgValuesSupported { get; set; } = null!; - } -} diff --git a/src/WalletFramework.SdJwtVc/Models/Records/SdJwtRecord.cs b/src/WalletFramework.SdJwtVc/Models/Records/SdJwtRecord.cs deleted file mode 100644 index 86d3c187..00000000 --- a/src/WalletFramework.SdJwtVc/Models/Records/SdJwtRecord.cs +++ /dev/null @@ -1,372 +0,0 @@ -using System.Collections.Immutable; -using System.IdentityModel.Tokens.Jwt; -using Hyperledger.Aries.Storage; -using LanguageExt; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Credentials.Abstractions; -using WalletFramework.Core.Cryptography.Models; -using WalletFramework.Core.Functional; -using WalletFramework.Core.StatusList; -using WalletFramework.SdJwtLib.Models; -using WalletFramework.SdJwtVc.Models.Credential; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; -using static WalletFramework.Core.Cryptography.Models.KeyId; - -namespace WalletFramework.SdJwtVc.Models.Records; - -/// -/// A record that represents a Selective Disclosure JSON Web Token (SD-JWT) Credential with additional properties. -/// Inherits from base class RecordBase. -/// -public sealed class SdJwtRecord : RecordBase, ICredential -{ - public const int CurrentVersion = 3; - - /// - /// Gets or sets the attributes that should be displayed. - /// - public Dictionary? DisplayedAttributes { get; set; } - - /// - /// Gets or sets the attributes that should be displayed. - /// - public List? AttributeOrder { get; set; } - - /// - /// Gets or sets the flattened structure of the claims in the credential. - /// The key is a JSON path to the claim value in the decoded SdJwtVc. - /// - public Dictionary Claims { get; set; } - - /// - /// Gets the disclosures. - /// - public ImmutableArray Disclosures { get; set; } - - /// - /// Gets or sets the display of the credential. - /// - public List? Display { get; set; } - - /// - /// Gets the Issuer-signed JWT part of the SD-JWT. - /// - public string EncodedIssuerSignedJwt { get; set; } = null!; - - /// - /// Tracks the state of the SD-JWT. - /// - public CredentialState CredentialState { get; set; } - - /// - /// Tracks whether it's a one-time use SD-JWT. - /// - public bool OneTimeUse { get; set; } - - /// - /// Tracks the Expiration Date of the Sd-JWT - /// - public DateTime? ExpiresAt { get; set; } - - /// - /// Tracks when the Sd-JWT was issued - /// - public DateTime? IssuedAt { get; set; } - - /// - /// Tracks when the Sd-JWT was issued - /// - public StatusListEntry? StatusListEntry { get; set; } - - /// - /// Tracks the Credential Format Identifier - /// - public string Format { get; set; } - - /// - /// Tracks when the Sd-JWT is valid from - /// - public DateTime? NotBefore { get; set; } - - //TODO: Use CredentialSetId Type instead fo string - public string CredentialSetId - { - get => Get(); - set => Set(value, false); - } - - /// - /// Gets or sets the identifier for the issuer. - /// - [JsonIgnore] - public string IssuerId - { - get => Get(); - set => Set(value, false); - } - - /// - /// Gets the key record ID. - /// - [JsonIgnore] - public Option KeyId - { - get - { - var str = Get(); - - return ValidKeyId(str).ToOption(); - } - private set - { - value.IfSome(keyId => Set((string)keyId)); - } - } - - /// - public override string TypeName => "AF.SdJwtRecord"; - - /// - /// Gets the verifiable credential type. - /// - [JsonIgnore] - public string Vct - { - get => Get(); - set => Set(value, false); - } - -#pragma warning disable CS8618 - /// - /// Parameterless Default Constructor. - /// - public SdJwtRecord() - { - } -#pragma warning restore CS8618 - - /// - /// Constructor for Serialization. - /// - /// The attributes that should be displayed. - /// The claims made. - /// The disclosures. - /// The display of the credential. - /// The Id of the issuer - /// The Issuer-signed JWT part of the SD-JWT. - /// The CredentialSetId. - /// The status list. - /// The Expiration Date. - /// The Issued at date. - /// The valid after date. - /// - /// The credential format identifier. - /// Indicator whether the credential should be sued only once. - [JsonConstructor] - public SdJwtRecord( - Dictionary? displayedAttributes, - Dictionary claims, - ImmutableArray disclosures, - List display, - string issuerId, - string encodedIssuerSignedJwt, - string credentialSetId, - StatusListEntry statusListEntry, - DateTime? expiresAt, - DateTime? issuedAt, - DateTime? notBefore, - int recordVersion, - string format, - bool isOneTimeUse = false) - { - Claims = claims; - Disclosures = disclosures; - - Display = display; - DisplayedAttributes = displayedAttributes; - - EncodedIssuerSignedJwt = encodedIssuerSignedJwt; - - ExpiresAt = expiresAt; - IssuedAt = issuedAt; - NotBefore = notBefore; - IssuerId = issuerId; - CredentialSetId = credentialSetId; - OneTimeUse = isOneTimeUse; - StatusListEntry = statusListEntry; - RecordVersion = recordVersion; - Format = format; - } - - public SdJwtRecord( - string serializedSdJwtWithDisclosures, - Dictionary? displayedAttributes, - List display, - Option keyId, - CredentialSetId credentialSetId, - bool isOneTimeUse = false) - { - Id = Guid.NewGuid().ToString(); - - var sdJwtDoc = new SdJwtDoc(serializedSdJwtWithDisclosures); - EncodedIssuerSignedJwt = sdJwtDoc.IssuerSignedJwt; - - var tokenHandler = new JwtSecurityTokenHandler(); - var token = tokenHandler.ReadJwtToken(EncodedIssuerSignedJwt); - Format = token.Header.Typ; - - Disclosures = sdJwtDoc.Disclosures.Select(x => x.Serialize()).ToImmutableArray(); - Claims = sdJwtDoc.GetAllSubjectClaims(); - Display = display; - DisplayedAttributes = displayedAttributes; - StatusListEntry = (sdJwtDoc.UnsecuredPayload.SelectToken("status")?.SelectToken("status_list")?.ToObject() - ?? sdJwtDoc.UnsecuredPayload.SelectToken("status")?.ToObject()) is not null - ? sdJwtDoc.UnsecuredPayload.SelectToken("status")?.SelectToken("status_list")?.ToObject() - ?? sdJwtDoc.UnsecuredPayload.SelectToken("status")?.ToObject() - : null; - - CredentialSetId = credentialSetId; - CredentialState = CredentialState.Active; - OneTimeUse = isOneTimeUse; - - KeyId = keyId; - ExpiresAt = sdJwtDoc.UnsecuredPayload.SelectToken("exp")?.Value() is not null - ? DateTimeOffset.FromUnixTimeSeconds(sdJwtDoc.UnsecuredPayload.SelectToken("exp")!.Value()).DateTime - : null; - IssuedAt = sdJwtDoc.UnsecuredPayload.SelectToken("iat")?.Value() is not null - ? DateTimeOffset.FromUnixTimeSeconds(sdJwtDoc.UnsecuredPayload.SelectToken("iat")!.Value()).DateTime - : null; - NotBefore = sdJwtDoc.UnsecuredPayload.SelectToken("nbf")?.Value() is not null - ? DateTimeOffset.FromUnixTimeSeconds(sdJwtDoc.UnsecuredPayload.SelectToken("nbf")!.Value()).DateTime - : null; - IssuerId = sdJwtDoc.UnsecuredPayload.SelectToken("iss")?.Value() - ?? throw new ArgumentNullException(nameof(IssuerId), "iss claim is missing or null"); - Vct = sdJwtDoc.UnsecuredPayload.SelectToken("vct")?.Value() - ?? throw new ArgumentNullException(nameof(Vct), "vct claim is missing or null"); - - RecordVersion = CurrentVersion; - } - - public SdJwtRecord( - SdJwtDoc sdJwtDoc, - Dictionary? displayedAttributes, - List display, - Option keyId, - CredentialSetId credentialSetId, - bool isOneTimeUse = false) - { - Id = Guid.NewGuid().ToString(); - - EncodedIssuerSignedJwt = sdJwtDoc.IssuerSignedJwt; - - var tokenHandler = new JwtSecurityTokenHandler(); - var token = tokenHandler.ReadJwtToken(EncodedIssuerSignedJwt); - Format = token.Header.Typ; - - Disclosures = sdJwtDoc.Disclosures.Select(disclosure => disclosure.Serialize()).ToImmutableArray(); - Claims = sdJwtDoc.GetAllSubjectClaims(); - Display = display; - DisplayedAttributes = displayedAttributes; - StatusListEntry = (sdJwtDoc.UnsecuredPayload.SelectToken("status")?.SelectToken("status_list")?.ToObject() - ?? sdJwtDoc.UnsecuredPayload.SelectToken("status")?.ToObject()) is not null - ? sdJwtDoc.UnsecuredPayload.SelectToken("status")?.SelectToken("status_list")?.ToObject() - ?? sdJwtDoc.UnsecuredPayload.SelectToken("status")?.ToObject() - : null; - - CredentialSetId = credentialSetId; - CredentialState = CredentialState.Active; - OneTimeUse = isOneTimeUse; - - KeyId = keyId; - - ExpiresAt = sdJwtDoc.UnsecuredPayload.SelectToken("exp")?.Value() is not null - ? DateTimeOffset.FromUnixTimeSeconds(sdJwtDoc.UnsecuredPayload.SelectToken("exp")!.Value()).DateTime - : null; - IssuedAt = sdJwtDoc.UnsecuredPayload.SelectToken("iat")?.Value() is not null - ? DateTimeOffset.FromUnixTimeSeconds(sdJwtDoc.UnsecuredPayload.SelectToken("iat")!.Value()).DateTime - : null; - NotBefore = sdJwtDoc.UnsecuredPayload.SelectToken("nbf")?.Value() is not null - ? DateTimeOffset.FromUnixTimeSeconds(sdJwtDoc.UnsecuredPayload.SelectToken("nbf")!.Value()).DateTime - : null; - IssuerId = sdJwtDoc.UnsecuredPayload.SelectToken("iss")?.Value() - ?? throw new ArgumentNullException(nameof(IssuerId), "iss claim is missing or null"); - Vct = sdJwtDoc.UnsecuredPayload.SelectToken("vct")?.Value() - ?? throw new ArgumentNullException(nameof(Vct), "vct claim is missing or null"); - - RecordVersion = CurrentVersion; - } - - public CredentialId GetId() - { - var id = CredentialId - .ValidCredentialId(Id) - .UnwrapOrThrow(new InvalidOperationException("SD-JWT RecordId is corrupt")); - - return id; - } - - public CredentialSetId GetCredentialSetId() => - Core.Credentials.CredentialSetId.ValidCredentialSetId(CredentialSetId) - .UnwrapOrThrow(new InvalidOperationException("The Id is corrupt")); -} - -internal static class JsonExtensions -{ - internal static Dictionary GetAllSubjectClaims(this SdJwtDoc sdJwtDoc) - { - var unsecuredPayload = (JObject)sdJwtDoc.UnsecuredPayload.DeepClone(); - - RemoveRegisteredClaims(unsecuredPayload); - - var allLeafClaims = GetLeafNodePaths(unsecuredPayload); - - return allLeafClaims.ToDictionary(key => key, key => unsecuredPayload.SelectToken(key)?.ToString() ?? string.Empty); - - void RemoveRegisteredClaims(JObject jObject) - { - string[] registeredClaims = { "iss", "sub", "aud", "exp", "nbf", "iat", "jti", "vct", "cnf", "status" }; - foreach (var claim in registeredClaims) - { - jObject.Remove(claim); - } - } - } - - private static List GetLeafNodePaths(JObject jObject) - { - var leafNodePaths = new List(); - - TraverseJToken(jObject, "", leafNodePaths); - - return leafNodePaths; - } - - private static void TraverseJToken(JToken token, string currentPath, List leafNodePaths) - { - switch (token.Type) - { - case JTokenType.Object: - foreach (var property in token.Children()) - { - TraverseJToken(property.Value, $"{currentPath}.{property.Name}", leafNodePaths); - } - break; - - case JTokenType.Array: - int index = 0; - foreach (var item in token.Children()) - { - TraverseJToken(item, $"{currentPath}[{index}]", leafNodePaths); - index++; - } - break; - - default: - //TODO decide if path without $ should be used -> currentPath.TrimStart('.') - leafNodePaths.Add(currentPath.TrimStart('.')); - break; - } - } -} diff --git a/src/WalletFramework.SdJwtVc/Models/Vct.cs b/src/WalletFramework.SdJwtVc/Models/Vct.cs index bd99993f..2af06a60 100644 --- a/src/WalletFramework.SdJwtVc/Models/Vct.cs +++ b/src/WalletFramework.SdJwtVc/Models/Vct.cs @@ -6,7 +6,7 @@ namespace WalletFramework.SdJwtVc.Models; -public readonly struct Vct +public readonly record struct Vct { private string Value { get; } diff --git a/src/WalletFramework.SdJwtVc/Persistence/FindSdJwtsBySetId.cs b/src/WalletFramework.SdJwtVc/Persistence/FindSdJwtsBySetId.cs new file mode 100644 index 00000000..37038984 --- /dev/null +++ b/src/WalletFramework.SdJwtVc/Persistence/FindSdJwtsBySetId.cs @@ -0,0 +1,15 @@ +using System.Linq.Expressions; +using WalletFramework.Core.Credentials; +using WalletFramework.Storage; + +namespace WalletFramework.SdJwtVc.Persistence; + +public sealed record FindSdJwtsBySetId(CredentialSetId CredentialSetId) + : ISearchConfig +{ + public Expression> ToPredicate() + { + var setId = CredentialSetId.AsString(); + return r => r.CredentialSetId == setId; + } +} diff --git a/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRecord.cs b/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRecord.cs new file mode 100644 index 00000000..89a5f668 --- /dev/null +++ b/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRecord.cs @@ -0,0 +1,78 @@ +using LanguageExt; +using Newtonsoft.Json; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Functional; +using WalletFramework.SdJwtLib.Models; +using WalletFramework.Storage.Records; + +namespace WalletFramework.SdJwtVc.Persistence; + +public record SdJwtCredentialRecord : RecordBase +{ + public string EncodedIssuerSignedJwt { get; init; } + + public string CredentialSetId { get; init; } + + public string? KeyId { get; init; } + + public string CredentialState { get; init; } + + public bool OneTimeUse { get; init; } + + public DateTime? ExpiresAt { get; init; } + + public string Vct { get; init; } + + public string? ClaimsJson { get; init; } + + public string? DisclosuresJson { get; init; } + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + // ReSharper disable once UnusedMember.Local + private SdJwtCredentialRecord() : base(Guid.NewGuid()) +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + { + } + + public SdJwtCredentialRecord(SdJwtCredential credential) : base(Guid.Parse(credential.CredentialId.AsString())) + { + EncodedIssuerSignedJwt = credential.EncodedIssuerSignedJwt; + CredentialSetId = credential.CredentialSetId.AsString(); + KeyId = credential.KeyId.ToNullable()?.AsString(); + Vct = credential.Vct.ToString(); + CredentialState = credential.CredentialState.ToString(); + OneTimeUse = credential.OneTimeUse; + ExpiresAt = credential.ExpiresAt.MatchUnsafe( + x => x, + () => (DateTime?)null); + ClaimsJson = JsonConvert.SerializeObject(credential.Claims); + DisclosuresJson = JsonConvert.SerializeObject(credential.Disclosures); + } + + public SdJwtCredential ToDomainModel() + { + var credentialId = CredentialId.ValidCredentialId(RecordId.ToString()).UnwrapOrThrow(); + var setId = Core.Credentials.CredentialSetId.ValidCredentialSetId(CredentialSetId).UnwrapOrThrow(); + var keyId = Core.Cryptography.Models.KeyId.ValidKeyId(KeyId).UnwrapOrThrow(); + var state = Enum.Parse(CredentialState); + var expires = ExpiresAt is null ? Option.None : Option.Some(ExpiresAt.Value); + + var disclosures = string.IsNullOrWhiteSpace(DisclosuresJson) + ? [] + : JsonConvert.DeserializeObject>(DisclosuresJson!) ?? []; + + var serializedSdJwtWithDisclosures = EncodedIssuerSignedJwt + + (disclosures.Count > 0 ? "~" + string.Join("~", disclosures) + "~" : "~"); + + var sdJwtDoc = new SdJwtDoc(serializedSdJwtWithDisclosures); + + return new SdJwtCredential( + sdJwtDoc, + credentialId, + setId, + keyId, + state, + OneTimeUse, + expires); + } +} diff --git a/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRecordConfiguration.cs b/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRecordConfiguration.cs new file mode 100644 index 00000000..0c3e786a --- /dev/null +++ b/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRecordConfiguration.cs @@ -0,0 +1,17 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Records; + +namespace WalletFramework.SdJwtVc.Persistence; + +public sealed record SdJwtCredentialRecordConfiguration : IRecordConfiguration +{ + public Unit Configure(ModelBuilder modelBuilder) + { + var entity = modelBuilder.Entity(); + entity.HasIndex(r => r.Vct); + entity.HasIndex(r => r.CredentialSetId); + + return Unit.Default; + } +} diff --git a/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRepository.cs b/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRepository.cs new file mode 100644 index 00000000..f57863f6 --- /dev/null +++ b/src/WalletFramework.SdJwtVc/Persistence/SdJwtCredentialRepository.cs @@ -0,0 +1,74 @@ +using LanguageExt; +using WalletFramework.Core.Credentials; +using WalletFramework.Storage; +using WalletFramework.Storage.Repositories; + +namespace WalletFramework.SdJwtVc.Persistence; + +public class SdJwtCredentialRepository(IRepository repository) + : IDomainRepository +{ + public async Task Add(SdJwtCredential domainModel) + { + return await (await GetById(domainModel.CredentialId)).Match( + async _ => await Update(domainModel), + async () => + { + var record = new SdJwtCredentialRecord(domainModel); + return await repository.Add(record); + }); + } + + public async Task AddMany(IEnumerable domainModels) + { + var records = domainModels.Select(domain => new SdJwtCredentialRecord(domain)); + await repository.AddMany(records); + return Unit.Default; + } + + public async Task> GetById(CredentialId id) + { + var guid = Guid.Parse(id.AsString()); + var record = await repository.GetById(guid); + return record.Map(r => r.ToDomainModel()); + } + + public async Task>> Find(ISearchConfig config) + { + var records = await repository.Find(config.ToPredicate()); + return + from credentialRecords in records + let credentials = credentialRecords.Select(r => r.ToDomainModel()) + select credentials.ToList(); + } + + public async Task>> ListAll() + { + var records = await repository.ListAll(); + return + from credentialRecords in records + let credentials = credentialRecords.Select(r => r.ToDomainModel()) + select credentials.ToList(); + } + + public async Task Update(SdJwtCredential domainModel) + { + var record = new SdJwtCredentialRecord(domainModel); + await repository.Update(record); + return Unit.Default; + } + + public async Task Delete(CredentialId id) + { + var guid = Guid.Parse(id.AsString()); + await repository.RemoveById(guid); + return Unit.Default; + } + + public async Task Delete(SdJwtCredential domainModel) + { + var record = new SdJwtCredentialRecord(domainModel); + await repository.Remove(record); + return Unit.Default; + } +} diff --git a/src/WalletFramework.SdJwtVc/SdJwtCredential.cs b/src/WalletFramework.SdJwtVc/SdJwtCredential.cs new file mode 100644 index 00000000..9ae36bba --- /dev/null +++ b/src/WalletFramework.SdJwtVc/SdJwtCredential.cs @@ -0,0 +1,159 @@ +using System.Collections.Immutable; +using System.IdentityModel.Tokens.Jwt; +using LanguageExt; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Credentials.Abstractions; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.Core.Functional; +using WalletFramework.Core.StatusList; +using WalletFramework.SdJwtLib.Models; +using WalletFramework.SdJwtVc.Models; + +namespace WalletFramework.SdJwtVc; + +public record SdJwtCredential : ICredential +{ + public bool OneTimeUse { get; init; } + + public CredentialId CredentialId { get; init; } + + public CredentialSetId CredentialSetId { get; init; } + + public CredentialState CredentialState { get; init; } + = CredentialState.Active; + + public Dictionary Claims { get; init; } = new(); + + public ImmutableArray Disclosures { get; init; } = ImmutableArray.Empty; + + public Option KeyId { get; init; } + + public Option ExpiresAt { get; init; } = Option.None; + + public Option IssuedAt { get; init; } = Option.None; + + public Option NotBefore { get; init; } = Option.None; + + public Option StatusListEntry { get; init; } = Option.None; + public string EncodedIssuerSignedJwt { get; init; } = string.Empty; + + public string Format { get; init; } = string.Empty; + + public string IssuerId { get; init; } = string.Empty; + + public Vct Vct { get; init; } + + public SdJwtDoc SdJwtDoc { get; init; } = null!; + + public SdJwtCredential( + SdJwtDoc sdJwtDoc, + CredentialId credentialId, + CredentialSetId credentialSetId, + Option keyId, + CredentialState credentialState, + bool oneTimeUse, + Option expiresAt) + { + EncodedIssuerSignedJwt = sdJwtDoc.IssuerSignedJwt; + SdJwtDoc = sdJwtDoc; + CredentialId = credentialId; + CredentialSetId = credentialSetId; + var vctValue = sdJwtDoc.UnsecuredPayload.SelectToken("vct")?.Value() + ?? throw new ArgumentNullException(nameof(Vct), "vct claim is missing or null"); + Vct = Vct.ValidVct(vctValue).UnwrapOrThrow(); + KeyId = keyId; + CredentialState = credentialState; + OneTimeUse = oneTimeUse; + ExpiresAt = expiresAt; + + var tokenHandler = new JwtSecurityTokenHandler(); + var token = tokenHandler.ReadJwtToken(EncodedIssuerSignedJwt); + + Format = token.Header.Typ; + + Disclosures = sdJwtDoc.Disclosures.Select(x => x.Serialize()).ToImmutableArray(); + Claims = GetAllSubjectClaims(sdJwtDoc); + + var status = sdJwtDoc.UnsecuredPayload.SelectToken("status")?.SelectToken("status_list") + ?.ToObject() + ?? sdJwtDoc.UnsecuredPayload.SelectToken("status")?.ToObject(); + StatusListEntry = status is not null + ? Option.Some(status) + : Option.None; + + IssuedAt = sdJwtDoc.UnsecuredPayload.SelectToken("iat")?.Value() is { } iat + ? Option.Some(DateTimeOffset.FromUnixTimeSeconds(iat).DateTime) + : Option.None; + + NotBefore = sdJwtDoc.UnsecuredPayload.SelectToken("nbf")?.Value() is { } nbf + ? Option.Some(DateTimeOffset.FromUnixTimeSeconds(nbf).DateTime) + : Option.None; + + IssuerId = sdJwtDoc.UnsecuredPayload.SelectToken("iss")?.Value() + ?? throw new ArgumentNullException(nameof(IssuerId), "iss claim is missing or null"); + } + + public CredentialSetId GetCredentialSetId() => CredentialSetId; + + public CredentialId GetId() => CredentialId; + + private static Dictionary GetAllSubjectClaims(SdJwtDoc sdJwtDoc) + { + var unsecuredPayload = (JObject)sdJwtDoc.UnsecuredPayload.DeepClone(); + + RemoveRegisteredClaims(unsecuredPayload); + + var allLeafClaims = GetLeafNodePaths(unsecuredPayload); + + return allLeafClaims.ToDictionary(key => key, + key => unsecuredPayload.SelectToken(key)?.ToString() ?? string.Empty); + + void RemoveRegisteredClaims(JObject jObject) + { + string[] registeredClaims = { "iss", "sub", "aud", "exp", "nbf", "iat", "jti", "vct", "cnf", "status" }; + foreach (var claim in registeredClaims) + { + jObject.Remove(claim); + } + } + } + + private static List GetLeafNodePaths(JObject jObject) + { + var leafNodePaths = new List(); + + TraverseJToken(jObject, "", leafNodePaths); + + return leafNodePaths; + } + + private static void TraverseJToken(JToken token, string currentPath, List leafNodePaths) + { + switch (token.Type) + { + case JTokenType.Object: + foreach (var property in token.Children()) + { + TraverseJToken(property.Value, $"{currentPath}.{property.Name}", leafNodePaths); + } + + break; + + case JTokenType.Array: + var index = 0; + foreach (var item in token.Children()) + { + TraverseJToken(item, $"{currentPath}[{index}]", leafNodePaths); + index++; + } + + break; + + default: + //TODO decide if path without $ should be used -> currentPath.TrimStart('.') + leafNodePaths.Add(currentPath.TrimStart('.')); + break; + } + } +} diff --git a/src/WalletFramework.SdJwtVc/SdJwtCredentialExtensions.cs b/src/WalletFramework.SdJwtVc/SdJwtCredentialExtensions.cs new file mode 100644 index 00000000..b1e36634 --- /dev/null +++ b/src/WalletFramework.SdJwtVc/SdJwtCredentialExtensions.cs @@ -0,0 +1,9 @@ +using WalletFramework.SdJwtLib.Models; + +namespace WalletFramework.SdJwtVc; + +public static class SdJwtCredentialExtensions +{ + public static SdJwtDoc ToSdJwtDoc(this SdJwtCredential record) => + new(record.EncodedIssuerSignedJwt + "~" + string.Join("~", record.Disclosures) + "~"); +} diff --git a/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/ISdJwtVcHolderService.cs b/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/ISdJwtVcHolderService.cs index 4c4edf62..45531d33 100644 --- a/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/ISdJwtVcHolderService.cs +++ b/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/ISdJwtVcHolderService.cs @@ -1,8 +1,4 @@ -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; using LanguageExt; -using WalletFramework.Core.Credentials; -using WalletFramework.SdJwtVc.Models.Records; namespace WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; @@ -11,16 +7,6 @@ namespace WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; /// public interface ISdJwtVcHolderService { - /// - /// Deletes a specific SD-JWT record by its ID. - /// - /// The agent context. - /// The ID of the SD-JWT credential record to delete. - /// - /// A task representing the asynchronous operation. The task result indicates whether the deletion was successful. - /// - Task DeleteAsync(IAgentContext context, string recordId); - /// /// Creates a SD-JWT in presentation format where the provided claims are disclosed. /// The key binding is optional and can be activated by providing an audience and a nonce. @@ -37,57 +23,11 @@ public interface ISdJwtVcHolderService /// The nonce /// The SD-JWT in presentation format Task CreatePresentation( - SdJwtRecord sdJwt, + SdJwtCredential sdJwt, string[] disclosedClaimPaths, Option> transactionDataBase64UrlStrings, Option> transactionDataHashes, Option transactionDataHashesAlg, string? audience = null, string? nonce = null); - - /// - /// Retrieves a specific SD-JWT record by its ID. - /// - /// The agent context. - /// The ID of the SD-JWT credential record to retrieve. - /// - /// A task representing the asynchronous operation. The task result contains the - /// associated with the given ID. - /// - Task GetAsync(IAgentContext context, string credentialId); - - /// - /// Lists SD-JWT records based on specified criteria. - /// - /// The agent context. - /// The search query to filter SD-JWT records. Default is null, meaning no filter. - /// The maximum number of records to retrieve. Default is 100. - /// The number of records to skip. Default is 0. - /// - /// A task representing the asynchronous operation. The task result contains a list of - /// that match the criteria. - /// - Task> ListAsync( - IAgentContext context, - ISearchQuery? query = null, - int count = 100, - int skip = 0); - - Task>> ListAsync(IAgentContext context, CredentialSetId setId); - - /// - /// Updates a SD-JWT record. - /// - /// The agent context. - /// The SD-JWT record to be saved - /// A task representing the asynchronous operation. The task result contains the ID of the stored JWT record. - Task UpdateAsync(IAgentContext context, SdJwtRecord record); - - /// - /// Adds a SD-JWT record. - /// - /// The agent context. - /// The SD-JWT record to be saved - /// A task representing the asynchronous operation. The task result contains the ID of the stored JWT record. - Task AddAsync(IAgentContext context, SdJwtRecord record); } diff --git a/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/SdJwtVcHolderService.cs b/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/SdJwtVcHolderService.cs index 130fe6d4..abb77089 100644 --- a/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/SdJwtVcHolderService.cs +++ b/src/WalletFramework.SdJwtVc/Services/SdJwtVcHolderService/SdJwtVcHolderService.cs @@ -1,28 +1,16 @@ -using Hyperledger.Aries; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; using LanguageExt; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Cryptography.Models; +using WalletFramework.Core.Functional; using WalletFramework.SdJwtLib.Models; using WalletFramework.SdJwtLib.Roles; -using WalletFramework.SdJwtVc.Models.Records; namespace WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; /// -public class SdJwtVcHolderService( - IHolder holder, - ISdJwtSigner signer, - IWalletRecordService recordService) : ISdJwtVcHolderService +public class SdJwtVcHolderService(IHolder holder, ISdJwtSigner signer) : ISdJwtVcHolderService { - /// - public virtual async Task AddAsync(IAgentContext context, SdJwtRecord record) => - await recordService.AddAsync(context.Wallet, record); - /// public async Task CreatePresentation( - SdJwtRecord credential, + SdJwtCredential credential, string[] disclosedClaimPaths, Option> transactionDataBase64UrlStrings, Option> transactionDataHashes, @@ -48,7 +36,7 @@ public async Task CreatePresentation( && !string.IsNullOrEmpty(audience)) { var keybindingJwt = await signer.GenerateKbProofOfPossessionAsync( - (KeyId)credential.KeyId, + credential.KeyId.UnwrapOrThrow(), audience, nonce, "kb+jwt", @@ -63,50 +51,4 @@ public async Task CreatePresentation( return presentationFormat.Value; } - - /// - public virtual async Task DeleteAsync(IAgentContext context, string recordId) => - await recordService.DeleteAsync(context.Wallet, recordId); - - /// - public async Task GetAsync(IAgentContext context, string credentialId) - { - var record = await recordService.GetAsync(context.Wallet, credentialId); - if (record == null) - throw new AriesFrameworkException(ErrorCode.RecordNotFound, "SD-JWT Credential record not found"); - - return record; - } - - /// - public Task> ListAsync( - IAgentContext context, - ISearchQuery? query = null, - int count = 100, - int skip = 0) => recordService.SearchAsync(context.Wallet, query, null, count, skip); - - public async Task>> ListAsync(IAgentContext context, CredentialSetId id) - { - var sdJwtQuery = SearchQuery.Equal( - "~" + nameof(SdJwtRecord.CredentialSetId), - id); - - var sdJwtRecords = await ListAsync( - context, - sdJwtQuery); - - return sdJwtRecords.Any() - ? sdJwtRecords - : Option>.None; - } - - /// - public virtual async Task UpdateAsync(IAgentContext context, SdJwtRecord record) => - await recordService.UpdateAsync(context.Wallet, record); -} - -public static class SdJwtRecordExtensions -{ - public static SdJwtDoc ToSdJwtDoc(this SdJwtRecord record) => - new(record.EncodedIssuerSignedJwt + "~" + string.Join("~", record.Disclosures) + "~"); } diff --git a/src/WalletFramework.SdJwtVc/WalletFramework.SdJwtVc.csproj b/src/WalletFramework.SdJwtVc/WalletFramework.SdJwtVc.csproj index 8fc5c44f..b33d6fdc 100644 --- a/src/WalletFramework.SdJwtVc/WalletFramework.SdJwtVc.csproj +++ b/src/WalletFramework.SdJwtVc/WalletFramework.SdJwtVc.csproj @@ -4,12 +4,13 @@ net8.0 enable enable + false - + diff --git a/src/WalletFramework.Storage.Unencrypted/DependencyInjection/ServiceCollectionExtensions.cs b/src/WalletFramework.Storage.Unencrypted/DependencyInjection/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..d6b86327 --- /dev/null +++ b/src/WalletFramework.Storage.Unencrypted/DependencyInjection/ServiceCollectionExtensions.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Storage.Providers; + +namespace WalletFramework.Storage.Unencrypted.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + /// + /// WARNING: This provider stores data without encryption. Do not use for sensitive data. + /// + public static IServiceCollection AddUnencryptedSqliteProvider( + this IServiceCollection services) + { + services.AddSingleton(); + return services; + } +} diff --git a/src/WalletFramework.Storage.Unencrypted/Sqlite3Provider.cs b/src/WalletFramework.Storage.Unencrypted/Sqlite3Provider.cs new file mode 100644 index 00000000..bb0745a0 --- /dev/null +++ b/src/WalletFramework.Storage.Unencrypted/Sqlite3Provider.cs @@ -0,0 +1,24 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using SQLitePCL; +using WalletFramework.Storage.Providers; + +namespace WalletFramework.Storage.Unencrypted; + +/// +/// WARNING: This provider stores data without encryption. Do not use for sensitive data. +/// +public sealed class Sqlite3Provider : ISqliteProvider +{ + public Unit Initialize() + { + Batteries_V2.Init(); + return Unit.Default; + } + + public Unit Configure(DbContextOptionsBuilder optionsBuilder, string connectionString) + { + optionsBuilder.UseSqlite(connectionString); + return Unit.Default; + } +} diff --git a/src/WalletFramework.Storage.Unencrypted/WalletFramework.Storage.Unencrypted.csproj b/src/WalletFramework.Storage.Unencrypted/WalletFramework.Storage.Unencrypted.csproj new file mode 100644 index 00000000..e0a4c882 --- /dev/null +++ b/src/WalletFramework.Storage.Unencrypted/WalletFramework.Storage.Unencrypted.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + WalletFramework.Storage.Unencrypted + + + + + + + + + + diff --git a/src/WalletFramework.Storage/Database/DatabaseCreator.cs b/src/WalletFramework.Storage/Database/DatabaseCreator.cs new file mode 100644 index 00000000..d17e7d45 --- /dev/null +++ b/src/WalletFramework.Storage/Database/DatabaseCreator.cs @@ -0,0 +1,39 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Database.Exceptions; + +namespace WalletFramework.Storage.Database; + +public sealed class DatabaseCreator(IDbContextFactory dbContextFactory) : IDatabaseCreator +{ + public async Task EnsureDatabaseCreated(CancellationToken cancellationToken = default) + { + await using var db = await dbContextFactory.CreateDbContextAsync(cancellationToken); + + var allMigrations = db.Database.GetMigrations(); + if (allMigrations.Any()) + { + try + { + await db.Database.MigrateAsync(cancellationToken); + return Unit.Default; + } + catch (Exception ex) + { + throw new DatabaseMigrationException($"Failed to apply migrations: {ex.Message}", ex); + } + } + else + { + try + { + await db.Database.EnsureCreatedAsync(cancellationToken); + return Unit.Default; + } + catch (Exception ex) + { + throw new DatabaseCreationException($"Failed to create database: {ex.Message}", ex); + } + } + } +} diff --git a/src/WalletFramework.Storage/Database/DependencyInjection/ServiceCollectionExtensions.cs b/src/WalletFramework.Storage/Database/DependencyInjection/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..b058e54c --- /dev/null +++ b/src/WalletFramework.Storage/Database/DependencyInjection/ServiceCollectionExtensions.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Storage.Providers; +using WalletFramework.Storage.Records; +using WalletFramework.Storage.Repositories; + +namespace WalletFramework.Storage.Database.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + /// + /// Creates a storage builder resolving the SQLite provider from DI so callers don't need to construct it. + /// + /// The service collection. + /// The SQLite connection string. + /// Action to configure the storage builder with records. + /// The service collection for chaining. + public static IServiceCollection ConfigureStorage( + this IServiceCollection services, + string connectionString, + Action configure) + { + var builder = new RecordsBuilder(services); + + builder.AddRecord(new RecordBaseConfiguration()); + + configure(builder); + + services.AddDbContextFactory((sp, options) => + { + var sqliteProvider = sp.GetRequiredService(); + sqliteProvider.Initialize(); + sqliteProvider.Configure(options, connectionString); + }); + + services.AddScoped(); + services.AddScoped(sp => sp.GetRequiredService()); + + services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); + + return services; + } +} diff --git a/src/WalletFramework.Storage/Database/Errors/DatabaseError.cs b/src/WalletFramework.Storage/Database/Errors/DatabaseError.cs new file mode 100644 index 00000000..e9c4ec1e --- /dev/null +++ b/src/WalletFramework.Storage/Database/Errors/DatabaseError.cs @@ -0,0 +1,5 @@ +using WalletFramework.Core.Functional; + +namespace WalletFramework.Storage.Database.Errors; + +public record DatabaseError(string Reason, Exception? Inner = null) : Error(Reason, Inner); diff --git a/src/WalletFramework.Storage/Database/Exceptions/DatabaseCreationException.cs b/src/WalletFramework.Storage/Database/Exceptions/DatabaseCreationException.cs new file mode 100644 index 00000000..0a980868 --- /dev/null +++ b/src/WalletFramework.Storage/Database/Exceptions/DatabaseCreationException.cs @@ -0,0 +1,9 @@ +namespace WalletFramework.Storage.Database.Exceptions; + +public sealed class DatabaseCreationException : Exception +{ + public DatabaseCreationException(string message) : base(message) { } + + public DatabaseCreationException(string message, Exception innerException) + : base(message, innerException) { } +} diff --git a/src/WalletFramework.Storage/Database/Exceptions/DatabaseMigrationException.cs b/src/WalletFramework.Storage/Database/Exceptions/DatabaseMigrationException.cs new file mode 100644 index 00000000..0ef3cdc8 --- /dev/null +++ b/src/WalletFramework.Storage/Database/Exceptions/DatabaseMigrationException.cs @@ -0,0 +1,9 @@ +namespace WalletFramework.Storage.Database.Exceptions; + +public sealed class DatabaseMigrationException : Exception +{ + public DatabaseMigrationException(string message) : base(message) { } + + public DatabaseMigrationException(string message, Exception innerException) + : base(message, innerException) { } +} diff --git a/src/WalletFramework.Storage/Database/IDatabaseCreator.cs b/src/WalletFramework.Storage/Database/IDatabaseCreator.cs new file mode 100644 index 00000000..054598a9 --- /dev/null +++ b/src/WalletFramework.Storage/Database/IDatabaseCreator.cs @@ -0,0 +1,8 @@ +using LanguageExt; + +namespace WalletFramework.Storage.Database; + +public interface IDatabaseCreator +{ + Task EnsureDatabaseCreated(CancellationToken cancellationToken = default); +} diff --git a/src/WalletFramework.Storage/Database/WalletDbContext.cs b/src/WalletFramework.Storage/Database/WalletDbContext.cs new file mode 100644 index 00000000..07602366 --- /dev/null +++ b/src/WalletFramework.Storage/Database/WalletDbContext.cs @@ -0,0 +1,18 @@ +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Storage.Database; + +public class WalletDbContext( + DbContextOptions options, + IEnumerable configurations) : DbContext(options) +{ + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + foreach (var configuration in configurations) + { + configuration.Configure(modelBuilder); + } + } +} diff --git a/src/WalletFramework.Storage/IDomainRepository.cs b/src/WalletFramework.Storage/IDomainRepository.cs new file mode 100644 index 00000000..c3d96297 --- /dev/null +++ b/src/WalletFramework.Storage/IDomainRepository.cs @@ -0,0 +1,23 @@ +using LanguageExt; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Storage; + +public interface IDomainRepository where TRecord : RecordBase +{ + Task Add(TDomainModel domainModel); + + Task AddMany(IEnumerable domainModels); + + Task> GetById(TId id); + + Task>> Find(ISearchConfig config); + + Task>> ListAll(); + + Task Update(TDomainModel domainModel); + + Task Delete(TId id); + + Task Delete(TDomainModel domainModel); +} diff --git a/src/WalletFramework.Storage/ISearchConfig.cs b/src/WalletFramework.Storage/ISearchConfig.cs new file mode 100644 index 00000000..f3df2889 --- /dev/null +++ b/src/WalletFramework.Storage/ISearchConfig.cs @@ -0,0 +1,16 @@ +using System.Linq.Expressions; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Storage; + +/// +/// A search configuration for a record type. +/// +/// The record type to search. +public interface ISearchConfig where TRecord : RecordBase +{ + /// + /// Converts the search configuration to a predicate. + /// + Expression> ToPredicate(); +} diff --git a/src/WalletFramework.Storage/Providers/ISqliteProvider.cs b/src/WalletFramework.Storage/Providers/ISqliteProvider.cs new file mode 100644 index 00000000..80a14e5a --- /dev/null +++ b/src/WalletFramework.Storage/Providers/ISqliteProvider.cs @@ -0,0 +1,19 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; + +namespace WalletFramework.Storage.Providers; + +public interface ISqliteProvider +{ + /// + /// Initializes the SQLite provider. + /// + Unit Initialize(); + + /// + /// Configures the SQLite provider. + /// + /// The options builder. + /// The connection string. + Unit Configure(DbContextOptionsBuilder optionsBuilder, string connectionString); +} diff --git a/src/WalletFramework.Storage/Records/IRecordConfiguration.cs b/src/WalletFramework.Storage/Records/IRecordConfiguration.cs new file mode 100644 index 00000000..7f7c2837 --- /dev/null +++ b/src/WalletFramework.Storage/Records/IRecordConfiguration.cs @@ -0,0 +1,22 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; + +namespace WalletFramework.Storage.Records; + +/// +/// Non-generic base interface for record configurations. +/// +public interface IRecordConfiguration +{ + /// + /// Configures the Entity Framework model for the record type. + /// + /// The model builder to configure. + Unit Configure(ModelBuilder modelBuilder); +} + +/// +/// Interface for configuring Entity Framework for a specific record type. +/// +/// The record type that implements IRecord and inherits from BaseRecord. +public interface IRecordConfiguration : IRecordConfiguration where TRecord : RecordBase; diff --git a/src/WalletFramework.Storage/Records/IRecordsBuilder.cs b/src/WalletFramework.Storage/Records/IRecordsBuilder.cs new file mode 100644 index 00000000..61497d4b --- /dev/null +++ b/src/WalletFramework.Storage/Records/IRecordsBuilder.cs @@ -0,0 +1,26 @@ +namespace WalletFramework.Storage.Records; + +/// +/// Builder interface for configuring wallet storage with records. +/// +public interface IRecordsBuilder +{ + /// + /// Adds a record configuration to the storage builder. + /// + /// The record type that implements IRecord and inherits from BaseRecord. + /// The configuration type that implements IRecordConfiguration<TRecord>. + /// The storage builder for chaining. + IRecordsBuilder AddRecord() + where TRecord : RecordBase + where TConfiguration : class, IRecordConfiguration; + + /// + /// Adds a record configuration instance to the storage builder. + /// + /// The record type that implements IRecord and inherits from BaseRecord. + /// The configuration instance. + /// The storage builder for chaining. + IRecordsBuilder AddRecord(IRecordConfiguration configuration) + where TRecord : RecordBase; +} diff --git a/src/WalletFramework.Storage/Records/RecordBase.cs b/src/WalletFramework.Storage/Records/RecordBase.cs new file mode 100644 index 00000000..97f7b97e --- /dev/null +++ b/src/WalletFramework.Storage/Records/RecordBase.cs @@ -0,0 +1,63 @@ +using System.ComponentModel.DataAnnotations; +using LanguageExt; + +namespace WalletFramework.Storage.Records; + +/// +/// Base record class that provides common properties for all storage entities. +/// +public abstract record RecordBase +{ + /// + /// Gets or initializes the timestamp when the record was created. + /// + public DateTimeOffset CreatedAt { get; init; } + + /// + /// Gets or initializes the timestamp when the record was last updated. + /// + public DateTimeOffset UpdatedAt { get; init; } + + /// + /// Gets or initializes the unique identifier for the record. + /// + [Key] + public Guid RecordId { get; init; } + + public Dictionary Tags { get; init; } + + /// + /// Constructor that allows setting a custom Id. + /// + /// The unique identifier for the record. + protected RecordBase(Guid recordId) + { + var now = DateTimeOffset.UtcNow; + + RecordId = recordId; + CreatedAt = now; + UpdatedAt = now; + Tags = []; + } + + public Option GetTag(string key, Func deserialize) + { + if (!Tags.TryGetValue(key, out var value)) + return Option.None; + + return deserialize(value); + } + + public Unit SetTag(string key, T value, Func serialize) + { + var stringValue = serialize(value); + Tags[key] = stringValue; + return Unit.Default; + } + + public Unit RemoveTag(string key) + { + Tags.Remove(key); + return Unit.Default; + } +} diff --git a/src/WalletFramework.Storage/Records/RecordBaseConfiguration.cs b/src/WalletFramework.Storage/Records/RecordBaseConfiguration.cs new file mode 100644 index 00000000..022bd7e5 --- /dev/null +++ b/src/WalletFramework.Storage/Records/RecordBaseConfiguration.cs @@ -0,0 +1,116 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using System.Text.Json; + +namespace WalletFramework.Storage.Records; + +/// +/// Entity Framework configuration for the BaseRecord class. +/// This sets up how records are stored in the database. +/// +public record RecordBaseConfiguration : IRecordConfiguration +{ + public Unit Configure(ModelBuilder modelBuilder) + { + var entity = modelBuilder.Entity(); + + entity.Property(r => r.RecordId).HasConversion(); + entity.HasKey(r => r.RecordId); + entity.HasIndex(r => r.RecordId); + + ConfigureTagsProperty(entity); + + return Unit.Default; + } + + /// + /// Configures how the Tags dictionary is stored and compared in the database. + /// + private static void ConfigureTagsProperty(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder entity) + { + var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + + var tagsConverter = new ValueConverter, string>( + tags => ConvertTagsToJson(tags), + json => ConvertJsonToTags(json)); + + var tagsComparer = new ValueComparer>( + (tags1, tags2) => AreTagsEqual(tags1, tags2), + tags => GetTagsHashCode(tags), + tags => CreateTagsSnapshot(tags)); + + entity.Property(r => r.Tags) + .HasConversion(tagsConverter, tagsComparer) + .HasColumnType("TEXT"); + } + + /// + /// Converts a dictionary of tags to a JSON string for database storage. + /// + private static string ConvertTagsToJson(Dictionary tags) + { + var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + return JsonSerializer.Serialize(tags, jsonOptions); + } + + /// + /// Converts a JSON string from the database back to a dictionary of tags. + /// + private static Dictionary ConvertJsonToTags(string json) + { + var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + + if (string.IsNullOrWhiteSpace(json)) + return new Dictionary(); + + var result = JsonSerializer.Deserialize>(json, jsonOptions); + return result ?? new Dictionary(); + } + + /// + /// Compares two tag dictionaries to see if they are equal. + /// + private static bool AreTagsEqual(Dictionary? tags1, Dictionary? tags2) + { + if (ReferenceEquals(tags1, tags2)) + return true; + + if (tags1 is null || tags2 is null) + return false; + + if (tags1.Count != tags2.Count) + return false; + + return !tags1.Except(tags2).Any(); + } + + /// + /// Generates a hash code for a tags dictionary. + /// + private static int GetTagsHashCode(Dictionary? tags) + { + if (tags is null) + return 0; + + var hash = 0; + foreach (var (key, value) in tags) + { + var keyHash = key?.GetHashCode() ?? 0; + var valueHash = value?.GetHashCode() ?? 0; + hash = HashCode.Combine(hash, keyHash, valueHash); + } + return hash; + } + + /// + /// Creates a snapshot copy of the tags dictionary for change tracking. + /// + private static Dictionary CreateTagsSnapshot(Dictionary? tags) + { + return tags is null + ? new Dictionary() + : new Dictionary(tags); + } +} diff --git a/src/WalletFramework.Storage/Records/RecordsBuilder.cs b/src/WalletFramework.Storage/Records/RecordsBuilder.cs new file mode 100644 index 00000000..f59fb660 --- /dev/null +++ b/src/WalletFramework.Storage/Records/RecordsBuilder.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace WalletFramework.Storage.Records; + +/// +/// Builder class for configuring wallet storage with records. +/// +public sealed class RecordsBuilder(IServiceCollection services) : IRecordsBuilder +{ + /// + public IRecordsBuilder AddRecord() + where TRecord : RecordBase + where TConfiguration : class, IRecordConfiguration + { + services.AddScoped, TConfiguration>(); + services.AddScoped(sp => sp.GetRequiredService>()); + return this; + } + + /// + public IRecordsBuilder AddRecord(IRecordConfiguration configuration) + where TRecord : RecordBase + { + services.AddScoped(_ => configuration); + services.AddScoped(sp => sp.GetRequiredService>()); + return this; + } +} diff --git a/src/WalletFramework.Storage/Repositories/IRepository.cs b/src/WalletFramework.Storage/Repositories/IRepository.cs new file mode 100644 index 00000000..cf422a30 --- /dev/null +++ b/src/WalletFramework.Storage/Repositories/IRepository.cs @@ -0,0 +1,60 @@ +using System.Linq.Expressions; +using LanguageExt; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Storage.Repositories; + +/// +/// Generic repository abstraction for working with persisted records. +/// +/// A record type derived from . +public interface IRepository where TRecord : RecordBase +{ + /// + /// Adds a new record. + /// + /// The record to add. + Task Add(TRecord record); + + /// + /// Adds multiple records. + /// + /// The records to add. + Task AddMany(IEnumerable records); + + /// + /// Returns records matching the given predicate. + /// + /// Filter expression to apply. + Task>> Find(Expression> predicate); + + /// + /// Retrieves a record by identifier. + /// + /// The record identifier. + /// An option of the record if found. + Task> GetById(Guid id); + + /// + /// Returns all records. + /// + Task>> ListAll(); + + /// + /// Removes a record. + /// + /// The record to remove. + Task Remove(TRecord record); + + /// + /// Removes a record by identifier. + /// + /// The record identifier. + Task RemoveById(Guid id); + + /// + /// Updates an existing record. + /// + /// The record to update. + Task Update(TRecord record); +} diff --git a/src/WalletFramework.Storage/Repositories/Repository.cs b/src/WalletFramework.Storage/Repositories/Repository.cs new file mode 100644 index 00000000..b0e185ca --- /dev/null +++ b/src/WalletFramework.Storage/Repositories/Repository.cs @@ -0,0 +1,98 @@ +using System.Linq.Expressions; +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Database; +using WalletFramework.Storage.Records; +using static LanguageExt.Prelude; + +namespace WalletFramework.Storage.Repositories; + +public sealed class Repository(IDbContextFactory dbContextFactory) : IRepository + where TRecord : RecordBase +{ + public async Task Add(TRecord record) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + await context.Set().AddAsync(record); + await context.SaveChangesAsync(); + return Unit.Default; + } + + public async Task AddMany(IEnumerable records) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + await context.Set().AddRangeAsync(records); + await context.SaveChangesAsync(); + return Unit.Default; + } + + public async Task>> Find(Expression> predicate) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + var results = await context + .Set() + .AsNoTracking() + .Where(predicate) + .ToListAsync(); + return results.Count == 0 ? Option>.None : results; + } + + public async Task> GetById(Guid id) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + var entity = await context + .Set() + .AsNoTracking() + .FirstOrDefaultAsync(e => e.RecordId == id); + return Optional(entity); + } + + public async Task>> ListAll() + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + var results = await context + .Set() + .AsNoTracking() + .ToListAsync(); + return results.Count == 0 ? Option>.None : results; + } + + public async Task Remove(TRecord record) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + context.Set().Remove(record); + await context.SaveChangesAsync(); + return Unit.Default; + } + + public async Task RemoveById(Guid id) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + var entity = await context.Set().FirstOrDefaultAsync(e => e.RecordId == id); + if (entity is null) + { + return Unit.Default; + } + + context.Set().Remove(entity); + await context.SaveChangesAsync(); + return Unit.Default; + } + + public async Task Update(TRecord record) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + + var oldRecord = await context.Set().AsNoTracking().SingleAsync(e => e.RecordId == record.RecordId); + + record = record with + { + CreatedAt = oldRecord.CreatedAt, + UpdatedAt = DateTimeOffset.Now + }; + + context.Set().Update(record); + await context.SaveChangesAsync(); + return Unit.Default; + } +} diff --git a/src/WalletFramework.Storage/WalletFramework.Storage.csproj b/src/WalletFramework.Storage/WalletFramework.Storage.csproj new file mode 100644 index 00000000..1ec64c66 --- /dev/null +++ b/src/WalletFramework.Storage/WalletFramework.Storage.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + diff --git a/src/WalletFramework.TestSamples/MdocSamples.cs b/src/WalletFramework.TestSamples/MdocSamples.cs new file mode 100644 index 00000000..15e7149c --- /dev/null +++ b/src/WalletFramework.TestSamples/MdocSamples.cs @@ -0,0 +1,52 @@ +using Newtonsoft.Json.Linq; + +namespace WalletFramework.TestSamples; + +public static class MdocSamples +{ + // Properties for assertion based on decoded mDOC + public static string DocType => "org.iso.18013.5.1.mDL"; + + public static string NameSpace => "org.iso.18013.5.1"; + + public static string GivenName => "John"; + + public static string FamilyName => "Doe"; + + public static string DigestAlgorithm => "SHA-256"; + + public static string Version => "1.0"; + + // Validity dates from the decoded mDOC + public static string ValidFrom => "2025-08-13T18:27:42.903Z"; + + public static string ValidUntil => "2030-01-30T15:38:01.569Z"; + + public static string Signed => "2025-08-13T18:27:42.903Z"; + + // Status list information + public static string StatusListUri => "https://test.io/status-lists?registryId=77196a2c-5fb3-42f3-9be0-1914cf9d8578"; + + // Sample IDs used in credential + public static string CredentialId => "11111111-1111-1111-1111-111111111111"; + + public static string CredentialSetId => "22222222-2222-2222-2222-222222222222"; + + public static string KeyId => "33333333-3333-3333-3333-333333333333"; + + public static string GetEncodedMdocSample() => + "omdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGxpc3N1ZXJTaWduZWSiamlzc3VlckF1dGiEQ6EBJqEYIVkECzCCBAcwggLvoAMCAQICFC91o6_IowD4Ur1EK5mg4nwHU3MHMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJERTEPMA0GA1UECAwGSGVzc2VuMRowGAYDVQQHDBFGcmFua2Z1cnQgYW0gTWFpbjEVMBMGA1UECgwMVGVzdCBDb21wYW55MRIwEAYDVQQLDAlUZXN0IFVuaXQxDTALBgNVBAMMBFRlc3QxHDAaBgkqhkiG9w0BCQEWDVRlc3RAdGVzdC5jb20wHhcNMjUwODE0MDY0OTM1WhcNMjYwODE0MDY0OTM1WjCBkjELMAkGA1UEBhMCREUxDzANBgNVBAgMBkhlc3NlbjEaMBgGA1UEBwwRRnJhbmtmdXJ0IGFtIE1haW4xFTATBgNVBAoMDFRlc3QgQ29tcGFueTESMBAGA1UECwwJVGVzdCBVbml0MQ0wCwYDVQQDDARUZXN0MRwwGgYJKoZIhvcNAQkBFg1UZXN0QHRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkniO5UBYYy8EFbenFoCw9dzvaRH7Pp4RSLqzV5shg2R1KZJEj03FJ_1ECjcnA6pThrw4V0uwiixLY7bQ5HDV-C9xHxO5GfbScoaRCsrwtm3JucPqQaVc4CgGk---kyp-fomFDmSqOTVqJLrNKMniA5ohIAorS6urB-dKgF8q5AZ_xe_KTCe9qeZ7JDxu_JxMR-7G4P9Ktq0buuyiRhW6hKzLioGzVPGrw79KNYdIUQgdlJmiLzwkYjPrrm-faPLTrzbBRDl_gX2wxS7kVmy_mESFvKMgnX95ae_wKL6Safzbeh3fbgcrPvYXjF2ZyLRSp7AbrYphu_GxOrSR2S8JAwIDAQABo1MwUTAdBgNVHQ4EFgQUUp_qjf-pvURVP-cWUuB9T7TnEkowHwYDVR0jBBgwFoAUUp_qjf-pvURVP-cWUuB9T7TnEkowDwYDVR0TAQH_BAUwAwEB_zANBgkqhkiG9w0BAQsFAAOCAQEAiJyQJrlLJnUBJXWSgQ5oyomSgZFNMUVmDXnL_RT5HByGS4M3Xj-Es3XoFepZQJdYlM1uZx6WWriwioJ3X9RbnznQDnLdC-wU50gIZ1uhiRth_FRRwfgr1aHYzKZg5sL_aEc9B76TRUAUSU8VYWBcladV7SQRqOY5QC9gOptGJUfHp6yKMJ9Di0K6NGdswH_medX0z9v_auOdOCHzvnd_4Kp5YuwdNYRDMeV90GUnqRlvLZAC7PVDbDB2XzIkGY1HmIRuWRRMJES0y2R_EYpGa2viO7PxMmLgPwPaHdOqMav2ibxWchIbfKP1Nr6bGQCxImqN5ZvfBJfPq2vog5fdxlkCDNgYWQIHp2d2ZXJzaW9uYzEuMG9kaWdlc3RBbGdvcml0aG1nU0hBLTI1Nmdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGx2YWx1ZURpZ2VzdHOhcW9yZy5pc28uMTgwMTMuNS4xogBYIDCuG2Pl0G2jwUJm-lpS-Wjt5Vgo_hE70NVYLWM2zhPWAVggpazwAlF4cX7j-NBzDHaflc9yBw5zEyANj-jvqqSWb7BtZGV2aWNlS2V5SW5mb6FpZGV2aWNlS2V5pAECIAEhWCAg-QilggJwXlxnOIFYB0klBZSvnJUAu89zM6p_y6jdkCJYIGZBs-z8vNggFIGbvJ6gjzyMEEype9bNEGLip_9MyRMCbHZhbGlkaXR5SW5mb6Nmc2lnbmVkwHgYMjAyNS0wOC0xM1QxODoyNzo0Mi45MDNaaXZhbGlkRnJvbcB4GDIwMjUtMDgtMTNUMTg6Mjc6NDIuOTAzWmp2YWxpZFVudGlswHgYMjAzMC0wMS0zMFQxNTozODowMS41NjlaZnN0YXR1c6Frc3RhdHVzX2xpc3SiY2lkeBkZIGN1cml4XGh0dHBzOi8vdGVzdC5jb25uZWN0b3IubGlzc2kuaW8vc3RhdHVzLWxpc3RzP3JlZ2lzdHJ5SWQ9NzcxOTZhMmMtNWZiMy00MmYzLTliZTAtMTkxNGNmOWQ4NTc4WECH6H12ua6wvdEY4Wb0zz0TA0Q9HOe0esZM7u3liFeZ784p_JCQh8JGSY9JzSB_G3P-VD6uCUF4Gz22FNkMhEpxam5hbWVTcGFjZXOhcW9yZy5pc28uMTgwMTMuNS4xgtgYWFKkaGRpZ2VzdElEAGZyYW5kb21Q4Ejotgk9siP1xWRe2w_YXnFlbGVtZW50SWRlbnRpZmllcmpnaXZlbl9uYW1lbGVsZW1lbnRWYWx1ZWRKb2hu2BhYUqRoZGlnZXN0SUQBZnJhbmRvbVAMjzFNR5dAQVKMrEtOdO5wcWVsZW1lbnRJZGVudGlmaWVya2ZhbWlseV9uYW1lbGVsZW1lbnRWYWx1ZWNEb2U"; + + public static string GetMdocCredentialSample() + { + return new JObject + { + { "mdoc", GetEncodedMdocSample() }, + { "credential_id", CredentialId }, + { "credential_set_id", CredentialSetId }, + { "key_id", KeyId }, + { "credential_state", "Active" }, + { "one_time_use", false } + }.ToString(); + } +} diff --git a/src/WalletFramework.TestSamples/WalletFramework.TestSamples.csproj b/src/WalletFramework.TestSamples/WalletFramework.TestSamples.csproj new file mode 100644 index 00000000..8dea7108 --- /dev/null +++ b/src/WalletFramework.TestSamples/WalletFramework.TestSamples.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + enable + enable + + + + + + diff --git a/src/WalletFramework.sln b/src/WalletFramework.sln index 5e5b2159..45192e5d 100644 --- a/src/WalletFramework.sln +++ b/src/WalletFramework.sln @@ -5,28 +5,6 @@ VisualStudioVersion = 16.0.29509.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aries", "Aries", "{73FF6DBD-5847-4F2D-94BE-196AE9A80228}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.Tests", "..\test\Hyperledger.Aries.Tests\Hyperledger.Aries.Tests.csproj", "{A930D0EF-8D15-447B-B8BC-32D29F06CF18}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries", "Hyperledger.Aries\Hyperledger.Aries.csproj", "{CC5370E0-290A-424B-8AB1-E022AC303479}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.TestHarness", "Hyperledger.Aries.TestHarness\Hyperledger.Aries.TestHarness.csproj", "{F758A7A6-F048-4B68-AA6A-35851F3048AE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.AspNetCore", "Hyperledger.Aries.AspNetCore\Hyperledger.Aries.AspNetCore.csproj", "{8E275FAC-8513-4027-A271-6EDD8404E800}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.Payments.SovrinToken", "Hyperledger.Aries.Payments.SovrinToken\Hyperledger.Aries.Payments.SovrinToken.csproj", "{78AACB12-E8C1-4B09-A547-DE60AA74D4CF}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Routing", "Routing", "{50CA144B-F3EE-4FFC-B07C-C0E5959DAA82}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.Routing", "Hyperledger.Aries.Routing\Hyperledger.Aries.Routing.csproj", "{B730DE35-80ED-4372-9D9F-23B14353150C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.Routing.Mediator", "Hyperledger.Aries.Routing.Mediator\Hyperledger.Aries.Routing.Mediator.csproj", "{D963131D-96EC-4DF5-8147-D77E75DCAE67}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.Routing.Edge", "Hyperledger.Aries.Routing.Edge\Hyperledger.Aries.Routing.Edge.csproj", "{B76E800A-C3C1-4E42-AC60-24F70AF304BE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperledger.Aries.AspNetCore.Contracts", "Hyperledger.Aries.AspNetCore.Contracts\Hyperledger.Aries.AspNetCore.Contracts.csproj", "{C35CAB46-4192-4BED-BB1A-0956B5136E96}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Oid4Vc", "Oid4Vc", "{615A7979-79AD-4485-805F-3F4B772510CD}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.SdJwtVc", "WalletFramework.SdJwtVc\WalletFramework.SdJwtVc.csproj", "{FE43A9CD-1E5B-4F1F-BA08-A4A7E9A131FD}" @@ -57,54 +35,36 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.IsoProximit EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.Core.Tests", "..\test\WalletFramework.Core.Tests\WalletFramework.Core.Tests.csproj", "{BBD79F15-66E1-47A2-819E-A0644F514E40}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Storage", "Storage", "{0C48B6EB-179A-47A8-B839-AF6D743015E7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.Storage", "WalletFramework.Storage\WalletFramework.Storage.csproj", "{FF8D91C6-9898-4B5E-8F70-194BCC508040}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.Storage.Tests", "..\test\WalletFramework.Storage.Tests\WalletFramework.Storage.Tests.csproj", "{906E432F-DED1-4710-80C2-41D7EA8378D0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.Storage.Unencrypted", "WalletFramework.Storage.Unencrypted\WalletFramework.Storage.Unencrypted.csproj", "{95B57AD6-1293-480E-9FC1-60D121EC7336}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.TestSamples", "WalletFramework.TestSamples\WalletFramework.TestSamples.csproj", "{80C143C1-B000-4025-A7BA-A23B20FE34D1}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SdJwt", "SdJwt", "{EC94F3B3-9321-4E5A-88F4-8B1C4E90F32C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.SdJwtLib", "WalletFramework.SdJwtLib\WalletFramework.SdJwtLib.csproj", "{01F973A3-ED07-4396-8DD9-71EA691A7301}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletFramework.SdJwtLib.Tests", "..\test\WalletFramework.SdJwtLib.Tests\WalletFramework.SdJwtLib.Tests.csproj", "{A738B5E0-959D-4A3B-A841-848961117C26}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Legacy", "Legacy", "{97FA5CC7-1EDF-4BD3-AEF1-A7BB130FE891}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hyperledger.Aries", "..\legacy\src\Hyperledger.Aries\Hyperledger.Aries.csproj", "{F95229A6-075D-46E2-B774-646C76A789E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hyperledger.Aries.Routing", "..\legacy\src\Hyperledger.Aries.Routing\Hyperledger.Aries.Routing.csproj", "{78679969-F4E7-4157-9921-9A6931EC8EB4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hyperledger.Aries.Routing.Edge", "..\legacy\src\Hyperledger.Aries.Routing.Edge\Hyperledger.Aries.Routing.Edge.csproj", "{D15500F7-64EA-41A5-A717-4366E9A956A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A930D0EF-8D15-447B-B8BC-32D29F06CF18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A930D0EF-8D15-447B-B8BC-32D29F06CF18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A930D0EF-8D15-447B-B8BC-32D29F06CF18}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A930D0EF-8D15-447B-B8BC-32D29F06CF18}.Release|Any CPU.Build.0 = Release|Any CPU - {CC5370E0-290A-424B-8AB1-E022AC303479}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC5370E0-290A-424B-8AB1-E022AC303479}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC5370E0-290A-424B-8AB1-E022AC303479}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC5370E0-290A-424B-8AB1-E022AC303479}.Release|Any CPU.Build.0 = Release|Any CPU - {F758A7A6-F048-4B68-AA6A-35851F3048AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F758A7A6-F048-4B68-AA6A-35851F3048AE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F758A7A6-F048-4B68-AA6A-35851F3048AE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F758A7A6-F048-4B68-AA6A-35851F3048AE}.Release|Any CPU.Build.0 = Release|Any CPU - {8E275FAC-8513-4027-A271-6EDD8404E800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E275FAC-8513-4027-A271-6EDD8404E800}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E275FAC-8513-4027-A271-6EDD8404E800}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E275FAC-8513-4027-A271-6EDD8404E800}.Release|Any CPU.Build.0 = Release|Any CPU - {78AACB12-E8C1-4B09-A547-DE60AA74D4CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {78AACB12-E8C1-4B09-A547-DE60AA74D4CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {78AACB12-E8C1-4B09-A547-DE60AA74D4CF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {78AACB12-E8C1-4B09-A547-DE60AA74D4CF}.Release|Any CPU.Build.0 = Release|Any CPU - {B730DE35-80ED-4372-9D9F-23B14353150C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B730DE35-80ED-4372-9D9F-23B14353150C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B730DE35-80ED-4372-9D9F-23B14353150C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B730DE35-80ED-4372-9D9F-23B14353150C}.Release|Any CPU.Build.0 = Release|Any CPU - {D963131D-96EC-4DF5-8147-D77E75DCAE67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D963131D-96EC-4DF5-8147-D77E75DCAE67}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D963131D-96EC-4DF5-8147-D77E75DCAE67}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D963131D-96EC-4DF5-8147-D77E75DCAE67}.Release|Any CPU.Build.0 = Release|Any CPU - {B76E800A-C3C1-4E42-AC60-24F70AF304BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B76E800A-C3C1-4E42-AC60-24F70AF304BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B76E800A-C3C1-4E42-AC60-24F70AF304BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B76E800A-C3C1-4E42-AC60-24F70AF304BE}.Release|Any CPU.Build.0 = Release|Any CPU - {C35CAB46-4192-4BED-BB1A-0956B5136E96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C35CAB46-4192-4BED-BB1A-0956B5136E96}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C35CAB46-4192-4BED-BB1A-0956B5136E96}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C35CAB46-4192-4BED-BB1A-0956B5136E96}.Release|Any CPU.Build.0 = Release|Any CPU {FE43A9CD-1E5B-4F1F-BA08-A4A7E9A131FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE43A9CD-1E5B-4F1F-BA08-A4A7E9A131FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {FE43A9CD-1E5B-4F1F-BA08-A4A7E9A131FD}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -153,6 +113,22 @@ Global {BBD79F15-66E1-47A2-819E-A0644F514E40}.Debug|Any CPU.Build.0 = Debug|Any CPU {BBD79F15-66E1-47A2-819E-A0644F514E40}.Release|Any CPU.ActiveCfg = Release|Any CPU {BBD79F15-66E1-47A2-819E-A0644F514E40}.Release|Any CPU.Build.0 = Release|Any CPU + {FF8D91C6-9898-4B5E-8F70-194BCC508040}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF8D91C6-9898-4B5E-8F70-194BCC508040}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF8D91C6-9898-4B5E-8F70-194BCC508040}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF8D91C6-9898-4B5E-8F70-194BCC508040}.Release|Any CPU.Build.0 = Release|Any CPU + {906E432F-DED1-4710-80C2-41D7EA8378D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {906E432F-DED1-4710-80C2-41D7EA8378D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {906E432F-DED1-4710-80C2-41D7EA8378D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {906E432F-DED1-4710-80C2-41D7EA8378D0}.Release|Any CPU.Build.0 = Release|Any CPU + {95B57AD6-1293-480E-9FC1-60D121EC7336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {95B57AD6-1293-480E-9FC1-60D121EC7336}.Debug|Any CPU.Build.0 = Debug|Any CPU + {95B57AD6-1293-480E-9FC1-60D121EC7336}.Release|Any CPU.ActiveCfg = Release|Any CPU + {95B57AD6-1293-480E-9FC1-60D121EC7336}.Release|Any CPU.Build.0 = Release|Any CPU + {80C143C1-B000-4025-A7BA-A23B20FE34D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80C143C1-B000-4025-A7BA-A23B20FE34D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80C143C1-B000-4025-A7BA-A23B20FE34D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80C143C1-B000-4025-A7BA-A23B20FE34D1}.Release|Any CPU.Build.0 = Release|Any CPU {01F973A3-ED07-4396-8DD9-71EA691A7301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {01F973A3-ED07-4396-8DD9-71EA691A7301}.Debug|Any CPU.Build.0 = Debug|Any CPU {01F973A3-ED07-4396-8DD9-71EA691A7301}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -161,21 +137,23 @@ Global {A738B5E0-959D-4A3B-A841-848961117C26}.Debug|Any CPU.Build.0 = Debug|Any CPU {A738B5E0-959D-4A3B-A841-848961117C26}.Release|Any CPU.ActiveCfg = Release|Any CPU {A738B5E0-959D-4A3B-A841-848961117C26}.Release|Any CPU.Build.0 = Release|Any CPU + {F95229A6-075D-46E2-B774-646C76A789E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F95229A6-075D-46E2-B774-646C76A789E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F95229A6-075D-46E2-B774-646C76A789E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F95229A6-075D-46E2-B774-646C76A789E3}.Release|Any CPU.Build.0 = Release|Any CPU + {78679969-F4E7-4157-9921-9A6931EC8EB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78679969-F4E7-4157-9921-9A6931EC8EB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78679969-F4E7-4157-9921-9A6931EC8EB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78679969-F4E7-4157-9921-9A6931EC8EB4}.Release|Any CPU.Build.0 = Release|Any CPU + {D15500F7-64EA-41A5-A717-4366E9A956A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D15500F7-64EA-41A5-A717-4366E9A956A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D15500F7-64EA-41A5-A717-4366E9A956A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D15500F7-64EA-41A5-A717-4366E9A956A3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A930D0EF-8D15-447B-B8BC-32D29F06CF18} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} - {CC5370E0-290A-424B-8AB1-E022AC303479} = {73FF6DBD-5847-4F2D-94BE-196AE9A80228} - {F758A7A6-F048-4B68-AA6A-35851F3048AE} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} - {8E275FAC-8513-4027-A271-6EDD8404E800} = {73FF6DBD-5847-4F2D-94BE-196AE9A80228} - {78AACB12-E8C1-4B09-A547-DE60AA74D4CF} = {73FF6DBD-5847-4F2D-94BE-196AE9A80228} - {B730DE35-80ED-4372-9D9F-23B14353150C} = {50CA144B-F3EE-4FFC-B07C-C0E5959DAA82} - {D963131D-96EC-4DF5-8147-D77E75DCAE67} = {50CA144B-F3EE-4FFC-B07C-C0E5959DAA82} - {B76E800A-C3C1-4E42-AC60-24F70AF304BE} = {50CA144B-F3EE-4FFC-B07C-C0E5959DAA82} - {C35CAB46-4192-4BED-BB1A-0956B5136E96} = {73FF6DBD-5847-4F2D-94BE-196AE9A80228} - {50CA144B-F3EE-4FFC-B07C-C0E5959DAA82} = {73FF6DBD-5847-4F2D-94BE-196AE9A80228} {E3A38EF1-E578-453C-B836-4C84695FE7CB} = {615A7979-79AD-4485-805F-3F4B772510CD} {FE43A9CD-1E5B-4F1F-BA08-A4A7E9A131FD} = {615A7979-79AD-4485-805F-3F4B772510CD} {8E8B8EFA-3AFE-4D17-B381-8C230A86DB88} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} @@ -188,8 +166,15 @@ Global {70DB749B-255A-4B71-8B76-BAD6B091DA7C} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} {0CF48F14-6FC3-4AD9-875D-27A96DAB34D3} = {A1DD69B3-DC35-43CF-AE14-D751722F074A} {BBD79F15-66E1-47A2-819E-A0644F514E40} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} + {FF8D91C6-9898-4B5E-8F70-194BCC508040} = {0C48B6EB-179A-47A8-B839-AF6D743015E7} + {906E432F-DED1-4710-80C2-41D7EA8378D0} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} + {95B57AD6-1293-480E-9FC1-60D121EC7336} = {0C48B6EB-179A-47A8-B839-AF6D743015E7} + {80C143C1-B000-4025-A7BA-A23B20FE34D1} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} {01F973A3-ED07-4396-8DD9-71EA691A7301} = {EC94F3B3-9321-4E5A-88F4-8B1C4E90F32C} {A738B5E0-959D-4A3B-A841-848961117C26} = {02ADBA96-A50C-44F0-A9D9-FA0629AA2DF4} + {F95229A6-075D-46E2-B774-646C76A789E3} = {97FA5CC7-1EDF-4BD3-AEF1-A7BB130FE891} + {78679969-F4E7-4157-9921-9A6931EC8EB4} = {97FA5CC7-1EDF-4BD3-AEF1-A7BB130FE891} + {D15500F7-64EA-41A5-A717-4366E9A956A3} = {97FA5CC7-1EDF-4BD3-AEF1-A7BB130FE891} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4FFA80F9-ADC6-40DB-BBD1-A522B8A68560} diff --git a/test/WalletFramework.Core.Tests/Path/ClaimPathTests.cs b/test/WalletFramework.Core.Tests/Path/ClaimPathTests.cs index c2b98d19..e25f5d8c 100644 --- a/test/WalletFramework.Core.Tests/Path/ClaimPathTests.cs +++ b/test/WalletFramework.Core.Tests/Path/ClaimPathTests.cs @@ -21,10 +21,13 @@ public void Can_Create_ClaimPath() } [Theory] - [InlineData(new[] {"name"}, "$.name")] - [InlineData(new[] {"address"}, "$.address")] - [InlineData(new[] {"address", "street_address"}, "$.address.street_address")] - [InlineData(new[] {"degree", null}, "$.degree")] + [InlineData(new object[] {"name"}, "$.name")] + [InlineData(new object[] {"address"}, "$.address")] + [InlineData(new object[] {"address", "street_address"}, "$.address.street_address")] + [InlineData(new object?[] {"degree", null}, "$.degree[*]")] + [InlineData(new object?[] {"degree", null, "type"}, "$.degree[*].type")] + [InlineData(new object[] {"degree", 1}, "$.degree[1]")] + [InlineData(new object[] {"degree", 1, "type"}, "$.degree[1].type")] public void Can_Convert_ClaimPath_To_JsonPath(object[] path, string expectedResult) { var jArray = new JArray(path); diff --git a/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/Dcql/DcqlServiceTests.cs b/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/Dcql/DcqlServiceTests.cs index ce5857c9..a9469fd3 100644 --- a/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/Dcql/DcqlServiceTests.cs +++ b/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/Dcql/DcqlServiceTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; +using LanguageExt; using Moq; using Newtonsoft.Json.Linq; using WalletFramework.Core.ClaimPaths; @@ -8,26 +7,25 @@ using WalletFramework.Core.Credentials.Abstractions; using WalletFramework.Core.Cryptography.Models; using WalletFramework.Core.Functional; +using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; using WalletFramework.Oid4Vc; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; using WalletFramework.Oid4Vc.Oid4Vp.Dcql.CredentialQueries; using WalletFramework.Oid4Vc.Oid4Vp.Dcql.Models; using WalletFramework.Oid4Vc.Oid4Vp.Dcql.Services; using WalletFramework.Oid4Vc.Oid4Vp.Models; using WalletFramework.Oid4Vc.Tests.Samples; +using WalletFramework.SdJwtVc; using WalletFramework.SdJwtLib.Roles.Implementation; -using WalletFramework.SdJwtVc.Models.Credential; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; -using WalletFramework.SdJwtVc.Models.Records; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; +using WalletFramework.SdJwtVc.Persistence; +using WalletFramework.Storage; namespace WalletFramework.Integration.Tests.Oid4Vp.Dcql; public class DcqlServiceTests { - private readonly Mock _agentProviderMock = new(); - private readonly Mock _mdocStorageMock = new(); - private readonly Mock _sdJwtVcHolderServiceMock = new(); + private readonly Mock> _mdocStorageMock = new(); + private readonly Mock> _sdJwtVcHolderServiceMock = new(); private static readonly CredentialSetId DriverLicenseCredentialSetId = CredentialSetId.CreateCredentialSetId(); private static readonly CredentialSetId DriverLicenseCredentialCloneSetId = CredentialSetId.CreateCredentialSetId(); @@ -36,13 +34,13 @@ public class DcqlServiceTests private static readonly CredentialSetId AlternativeNestedCredentialSetId = CredentialSetId.CreateCredentialSetId(); private static readonly CredentialSetId BatchCredentialSetId = CredentialSetId.CreateCredentialSetId(); - private readonly SdJwtRecord _driverCredential = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialSetId); - private readonly SdJwtRecord _driverCredentialClone = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialCloneSetId); - private readonly SdJwtRecord _universityCredential = CreateCredential(JsonBasedCredentialSamples.UniversityCredential, UniversityCredentialSetId); - private readonly SdJwtRecord _nestedCredential = CreateCredential(JsonBasedCredentialSamples.NestedCredential, NestedCredentialSetId); - private readonly SdJwtRecord _alternativeNestedCredential = CreateCredential(JsonBasedCredentialSamples.AlternativeNestedCredential, AlternativeNestedCredentialSetId); - private readonly SdJwtRecord _batchCredentialOne = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); - private readonly SdJwtRecord _batchCredentialTwo = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); + private readonly SdJwtCredential _driverCredential = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialSetId); + private readonly SdJwtCredential _driverCredentialClone = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialCloneSetId); + private readonly SdJwtCredential _universityCredential = CreateCredential(JsonBasedCredentialSamples.UniversityCredential, UniversityCredentialSetId); + private readonly SdJwtCredential _nestedCredential = CreateCredential(JsonBasedCredentialSamples.NestedCredential, NestedCredentialSetId); + private readonly SdJwtCredential _alternativeNestedCredential = CreateCredential(JsonBasedCredentialSamples.AlternativeNestedCredential, AlternativeNestedCredentialSetId); + private readonly SdJwtCredential _batchCredentialOne = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); + private readonly SdJwtCredential _batchCredentialTwo = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); [Fact] public async Task Can_Get_Credential_Candidates_For_CredentialQuery() @@ -217,8 +215,8 @@ public async Task Cant_Get_Credential_Candidates_When_Not_All_CredentialClaimQue private IDcqlService CreateDcqlService() { _sdJwtVcHolderServiceMock - .Setup(x => x.ListAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(() => new List + .Setup(x => x.ListAll()) + .ReturnsAsync(() => new List { _driverCredential, _driverCredentialClone, @@ -229,22 +227,24 @@ private IDcqlService CreateDcqlService() _batchCredentialTwo }); - return new DcqlService(_agentProviderMock.Object, _mdocStorageMock.Object, _sdJwtVcHolderServiceMock.Object); + return new DcqlService(_mdocStorageMock.Object, _sdJwtVcHolderServiceMock.Object); } - private static SdJwtRecord CreateCredential(JObject payload, CredentialSetId credentialSetId) + private static SdJwtCredential CreateCredential(JObject payload, CredentialSetId credentialSetId) { // Arrange const string jwk = "{\"kty\":\"EC\",\"d\":\"1_2Dagk1gvTIOX-DLPe7GHNsGLJMc7biySNA-so7TXE\",\"use\":\"sig\",\"crv\":\"P-256\",\"x\":\"X6sZhH_kFp_oKYiPXW-LvUyAv9mHp1xYcpAK3yy0wGY\",\"y\":\"p0URU7tgWbh42miznti0NVKM36fpJBbIfnF8ZCYGryE\",\"alg\":\"ES256\"}"; var issuedSdJwt = new Issuer().IssueCredential(payload, jwk); var keyId = KeyId.CreateKeyId(); - var record = new SdJwtRecord( - issuedSdJwt.IssuanceFormat, - new Dictionary(), - new List(), + var record = new SdJwtCredential( + issuedSdJwt, + CredentialId.CreateCredentialId(), + credentialSetId, keyId, - credentialSetId); + CredentialState.Active, + false, + Option.None); return record; } diff --git a/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/PresentationExchange/Services/PexServiceTests.cs b/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/PresentationExchange/Services/PexServiceTests.cs index 23aece02..5027b076 100644 --- a/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/PresentationExchange/Services/PexServiceTests.cs +++ b/test/WalletFramework.Integration.Tests/WalletFramework.Integration.Tests/Oid4Vp/PresentationExchange/Services/PexServiceTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; -using Hyperledger.Aries.Agents; -using Hyperledger.Aries.Storage; +using LanguageExt; using Moq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -9,7 +8,8 @@ using WalletFramework.Core.Cryptography.Models; using WalletFramework.Core.Functional; using WalletFramework.Integration.Tests.Oid4Vp.PresentationExchange.Models; -using WalletFramework.Oid4Vc.Oid4Vci.Abstractions; +using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models; using WalletFramework.Oid4Vc.Oid4Vp.Models; using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models; @@ -17,18 +17,16 @@ using WalletFramework.Oid4Vc.Tests.Extensions; using WalletFramework.Oid4Vc.Tests.Samples; using WalletFramework.SdJwtLib.Roles.Implementation; -using WalletFramework.SdJwtVc.Models.Credential; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; -using WalletFramework.SdJwtVc.Models.Records; -using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; +using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Persistence; +using WalletFramework.Storage; namespace WalletFramework.Integration.Tests.Oid4Vp.PresentationExchange.Services; public class PexServiceTests { - private readonly Mock _agentProviderMock = new(); - private readonly Mock _mdocStorageMock = new(); - private readonly Mock _sdJwtVcHolderServiceMock = new(); + private readonly Mock> _mdocRepository = new(); + private readonly Mock> _sdJwtRepository = new(); private static readonly CredentialSetId DriverLicenseCredentialSetId = CredentialSetId.CreateCredentialSetId(); private static readonly CredentialSetId DriverLicenseCredentialCloneSetId = CredentialSetId.CreateCredentialSetId(); @@ -37,13 +35,13 @@ public class PexServiceTests private static readonly CredentialSetId AlternativeNestedCredentialSetId = CredentialSetId.CreateCredentialSetId(); private static readonly CredentialSetId BatchCredentialSetId = CredentialSetId.CreateCredentialSetId(); - private readonly SdJwtRecord _driverCredential = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialSetId); - private readonly SdJwtRecord _driverCredentialClone = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialCloneSetId); - private readonly SdJwtRecord _universityCredential = CreateCredential(JsonBasedCredentialSamples.UniversityCredential, UniversityCredentialSetId); - private readonly SdJwtRecord _nestedCredential = CreateCredential(JsonBasedCredentialSamples.NestedCredential, NestedCredentialSetId); - private readonly SdJwtRecord _alternativeNestedCredential = CreateCredential(JsonBasedCredentialSamples.AlternativeNestedCredential, AlternativeNestedCredentialSetId); - private readonly SdJwtRecord _batchCredentialOne = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); - private readonly SdJwtRecord _batchCredentialTwo = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); + private readonly SdJwtCredential _driverCredential = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialSetId); + private readonly SdJwtCredential _driverCredentialClone = CreateCredential(JsonBasedCredentialSamples.DriverCredential, DriverLicenseCredentialCloneSetId); + private readonly SdJwtCredential _universityCredential = CreateCredential(JsonBasedCredentialSamples.UniversityCredential, UniversityCredentialSetId); + private readonly SdJwtCredential _nestedCredential = CreateCredential(JsonBasedCredentialSamples.NestedCredential, NestedCredentialSetId); + private readonly SdJwtCredential _alternativeNestedCredential = CreateCredential(JsonBasedCredentialSamples.AlternativeNestedCredential, AlternativeNestedCredentialSetId); + private readonly SdJwtCredential _batchCredentialOne = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); + private readonly SdJwtCredential _batchCredentialTwo = CreateCredential(JsonBasedCredentialSamples.BatchCredential, BatchCredentialSetId); [Fact] public async Task Can_Create_Authorization_Response() @@ -81,26 +79,24 @@ public async Task Can_Get_Credential_Candidates_For_Input_Descriptors() idFilter.PrivateSet(x => x.Const, "123"); var batchInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] - { CreateField("$.id", idFilter), CreateField("$.issuer"), CreateField("$.batchExp") }), - CreateFormat(new[] { "ES256" }), + CreateConstraints([CreateField("$.id", idFilter), CreateField("$.issuer"), CreateField("$.batchExp")]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "EU Driver's License", "We can only accept digital driver's licenses issued by national authorities of member states or trusted notarial auditors.", - new[] { "A" }); + ["A"]); var driverLicenseInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] - { CreateField("$.id", idFilter), CreateField("$.issuer"), CreateField("$.dateOfBirth") }), - CreateFormat(new[] { "ES256" }), + CreateConstraints([CreateField("$.id", idFilter), CreateField("$.issuer"), CreateField("$.dateOfBirth")]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "EU Driver's License", "We can only accept digital driver's licenses issued by national authorities of member states or trusted notarial auditors.", - new[] { "A" }); + ["A"]); var universityInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] { CreateField("$.degree") }), - CreateFormat(new[] { "ES256" }), + CreateConstraints([CreateField("$.degree")]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "University Degree", "We can only accept digital university degrees."); @@ -149,13 +145,12 @@ public async Task Can_Get_Credential_Candidates_For_Input_Descriptors_With_Neste idFilter.PrivateSet(x => x.Const, "Berlin"); var identityCredentialInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] - { CreateField("$.address.city", idFilter), CreateField("$.vct"), CreateField("$.iss") }), - CreateFormat(new[] { "ES256" }), + CreateConstraints([CreateField("$.address.city", idFilter), CreateField("$.vct"), CreateField("$.iss")]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "Identity Credential", "We can only accept digital identity credentials.", - new[] { "A" }); + ["A"]); var expected = new List { @@ -186,13 +181,12 @@ public async Task Can_Get_Multiple_Credential_Candidates_For_Input_Descriptors_W vctFilter.PrivateSet(x => x.Const, "IdentityCredential"); var identityCredentialInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] - { CreateField("$.address.city"), CreateField("$.vct", vctFilter), CreateField("$.iss") }), - CreateFormat(new[] { "ES256" }), + CreateConstraints([CreateField("$.address.city"), CreateField("$.vct", vctFilter), CreateField("$.iss")]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "Identity Credential", "We can only accept digital identity credentials.", - new[] { "A" }); + ["A"]); var expected = new List { @@ -219,12 +213,12 @@ public async Task Can_Get_Credential_Candidates_For_Input_Descriptors_With_Enum_ new List { _universityCredential }); var enumVctFilter = new Filter(); - enumVctFilter.PrivateSet(x => x.Enum, new[] { "UniversityDegreeCredential", "vctTypeTwo" }); + enumVctFilter.PrivateSet(x => x.Enum, ["UniversityDegreeCredential", "vctTypeTwo"]); enumVctFilter.PrivateSet(x => x.Type, "string"); var universityInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] { CreateField("$.degree"), CreateField("$.vct", enumVctFilter) }), - CreateFormat(new[] { "ES256" }), + CreateConstraints([CreateField("$.degree"), CreateField("$.vct", enumVctFilter)]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "University Degree", "We can only accept digital university degrees."); @@ -251,12 +245,12 @@ public async Task Can_Get_Credential_Candidates_For_Input_Descriptors_With_Enum_ public async Task Cant_Get_Credential_Candidates_For_Input_Descriptors_With_Enum_Filter_Not_Fulfilled() { var enumVctFilter = new Filter(); - enumVctFilter.PrivateSet(x => x.Enum, new[] { "vctTypeTwo", "vctTypeTwo" }); + enumVctFilter.PrivateSet(x => x.Enum, ["vctTypeTwo", "vctTypeTwo"]); enumVctFilter.PrivateSet(x => x.Type, "string"); var universityInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] { CreateField("$.degree"), CreateField("$.vct", enumVctFilter) }), - CreateFormat(new[] { "ES256" }), + CreateConstraints([CreateField("$.degree"), CreateField("$.vct", enumVctFilter)]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "University Degree", "We can only accept digital university degrees."); @@ -275,12 +269,11 @@ public async Task Cant_Get_Credential_Candidates_When_Not_All_Fields_Are_Fulfill { // Arrange var driverLicenseInputDescriptor = CreateInputDescriptor( - CreateConstraints(new[] - { + CreateConstraints([ CreateField("$.id"), CreateField("$.issuer"), CreateField("$.dateOfBirth"), CreateField("$.name") - }), - CreateFormat(new[] { "ES256" }), + ]), + CreateFormat(["ES256"]), Guid.NewGuid().ToString(), "EU Driver's License", "We can only accept digital driver's licenses issued by national authorities of member states or trusted notarial auditors."); @@ -320,9 +313,9 @@ public async Task Cant_Get_Credential_Candidates_When_Not_All_Filters_Are_Fulfil private IPexService CreatePexService() { - _sdJwtVcHolderServiceMock - .Setup(x => x.ListAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(() => new List + _sdJwtRepository + .Setup(x => x.ListAll()) + .ReturnsAsync(() => new List { _driverCredential, _driverCredentialClone, @@ -333,22 +326,24 @@ private IPexService CreatePexService() _batchCredentialTwo }); - return new PexService(_agentProviderMock.Object, _mdocStorageMock.Object, _sdJwtVcHolderServiceMock.Object); + return new PexService(_mdocRepository.Object, _sdJwtRepository.Object); } - private static SdJwtRecord CreateCredential(JObject payload, CredentialSetId credentialSetId) + private static SdJwtCredential CreateCredential(JObject payload, CredentialSetId credentialSetId) { // Arrange const string jwk = "{\"kty\":\"EC\",\"d\":\"1_2Dagk1gvTIOX-DLPe7GHNsGLJMc7biySNA-so7TXE\",\"use\":\"sig\",\"crv\":\"P-256\",\"x\":\"X6sZhH_kFp_oKYiPXW-LvUyAv9mHp1xYcpAK3yy0wGY\",\"y\":\"p0URU7tgWbh42miznti0NVKM36fpJBbIfnF8ZCYGryE\",\"alg\":\"ES256\"}"; var issuedSdJwt = new Issuer().IssueCredential(payload, jwk); var keyId = KeyId.CreateKeyId(); - var record = new SdJwtRecord( - issuedSdJwt.IssuanceFormat, - new Dictionary(), - new List(), + var record = new SdJwtCredential( + issuedSdJwt, + CredentialId.CreateCredentialId(), + credentialSetId, keyId, - credentialSetId); + CredentialState.Active, + false, + Option.None); return record; } @@ -364,7 +359,7 @@ private static Constraints CreateConstraints(Field[] fields) private static Field CreateField(string path, Filter? filter = null) { var field = new Field(); - field.PrivateSet(x => x.Path, new[] { path }); + field.PrivateSet(x => x.Path, [path]); if (filter != null) { diff --git a/test/WalletFramework.MdocVc.Tests/MdocCredentialTests.cs b/test/WalletFramework.MdocVc.Tests/MdocCredentialTests.cs new file mode 100644 index 00000000..dd9d1763 --- /dev/null +++ b/test/WalletFramework.MdocVc.Tests/MdocCredentialTests.cs @@ -0,0 +1,153 @@ +using WalletFramework.Core.Functional; +using WalletFramework.MdocLib; +using WalletFramework.TestSamples; +using WalletFramework.MdocVc.Serialization; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Cryptography.Models; +using FluentAssertions; +using Newtonsoft.Json.Linq; +using LanguageExt; +using WalletFramework.MdocVc.Persistence; +using Xunit; + +namespace WalletFramework.MdocVc.Tests; + +public class MdocCredentialTests +{ + [Fact] + public void Can_Serialize_MdocCredential() + { + // Arrange + var mdoc = Mdoc.ValidMdoc(MdocSamples.GetEncodedMdocSample()).UnwrapOrThrow(); + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + var credential = new MdocCredential( + mdoc, + credentialId, + credentialSetId, + keyId, + CredentialState.Active, + false, + Option.None + ); + + // Act + var sut = MdocCredentialSerializer.Serialize(credential); + + // Assert + var jObject = JObject.Parse(sut); + jObject[MdocCredentialSerializationConstants.MdocJsonKey]!.ToString().Should().Be(mdoc.Encode()); + jObject[MdocCredentialSerializationConstants.CredentialIdJsonKey]!.ToString().Should().Be(credentialId.AsString()); + jObject[MdocCredentialSerializationConstants.KeyIdJsonKey]!.ToString().Should().Be(keyId.AsString()); + jObject[MdocCredentialSerializationConstants.CredentialStateJsonKey]!.ToString().Should().Be(CredentialState.Active.ToString()); + + } + + [Fact] + public void Can_Deserialize_MdocCredential() + { + // Arrange + var json = MdocSamples.GetMdocCredentialSample(); + + // Act + var sut = MdocCredentialSerializer.Deserialize(json).UnwrapOrThrow(); + + // Assert + sut.CredentialState.Should().Be(CredentialState.Active); + sut.OneTimeUse.Should().BeFalse(); + sut.Mdoc.DocType.AsString().Should().Be(MdocSamples.DocType); + sut.CredentialId.AsString().Should().Be(MdocSamples.CredentialId); + sut.CredentialSetId.AsString().Should().Be(MdocSamples.CredentialSetId); + sut.KeyId.AsString().Should().Be(MdocSamples.KeyId); + + // Assert mDOC structure + var nameSpace = NameSpace.ValidNameSpace(MdocSamples.NameSpace).UnwrapOrThrow(); + var issuerNameSpaces = sut.Mdoc.IssuerSigned.IssuerNameSpaces; + issuerNameSpaces.Value.Should().ContainKey(nameSpace); + + var items = issuerNameSpaces[nameSpace]; + var givenNameItem = items.FirstOrDefault(item => item.ElementId.Value == "given_name"); + var familyNameItem = items.FirstOrDefault(item => item.ElementId.Value == "family_name"); + + givenNameItem.Should().NotBeNull(); + familyNameItem.Should().NotBeNull(); + givenNameItem!.Element.ToString().Should().Be(MdocSamples.GivenName); + familyNameItem!.Element.ToString().Should().Be(MdocSamples.FamilyName); + } + + [Fact] + public void Can_Map_To_Record() + { + // Arrange + var mdoc = Mdoc.ValidMdoc(MdocSamples.GetEncodedMdocSample()).UnwrapOrThrow(); + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + var credential = new MdocCredential( + mdoc, + credentialId, + credentialSetId, + keyId, + CredentialState.Active, + false, + Option.None); + + // Act + var sut = new MdocCredentialRecord(credential); + + // Assert + sut.DocType.Should().Be(mdoc.DocType.AsString()); + sut.DocType.Should().Be(MdocSamples.DocType); + + // Verify that the serialized data contains the correct credential information + var deserializedCredential = sut.ToDomainModel(); + deserializedCredential.CredentialId.AsString().Should().Be(credentialId.AsString()); + deserializedCredential.CredentialSetId.AsString().Should().Be(credentialSetId.AsString()); + deserializedCredential.KeyId.AsString().Should().Be(keyId.AsString()); + } + + [Fact] + public void Can_Map_From_Record() + { + // Arrange + var mdoc = Mdoc.ValidMdoc(MdocSamples.GetEncodedMdocSample()).UnwrapOrThrow(); + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + var credential = new MdocCredential( + mdoc, + credentialId, + credentialSetId, + keyId, + CredentialState.Active, + false, + Option.None + ); + + // Act + var sut = new MdocCredentialRecord(credential).ToDomainModel(); + + // Assert + sut.CredentialState.Should().Be(CredentialState.Active); + sut.OneTimeUse.Should().BeFalse(); + sut.Mdoc.DocType.AsString().Should().Be(MdocSamples.DocType); + sut.CredentialId.AsString().Should().Be(credentialId); + sut.CredentialSetId.AsString().Should().Be(credentialSetId); + sut.KeyId.AsString().Should().Be(keyId); + + // Assert mDOC structure + var nameSpace = NameSpace.ValidNameSpace(MdocSamples.NameSpace).UnwrapOrThrow(); + var issuerNameSpaces = sut.Mdoc.IssuerSigned.IssuerNameSpaces; + issuerNameSpaces.Value.Should().ContainKey(nameSpace); + + var items = issuerNameSpaces[nameSpace]; + var givenNameItem = items.FirstOrDefault(item => item.ElementId.Value == "given_name"); + var familyNameItem = items.FirstOrDefault(item => item.ElementId.Value == "family_name"); + + givenNameItem.Should().NotBeNull(); + familyNameItem.Should().NotBeNull(); + givenNameItem!.Element.ToString().Should().Be(MdocSamples.GivenName); + familyNameItem!.Element.ToString().Should().Be(MdocSamples.FamilyName); + } +} diff --git a/test/WalletFramework.MdocVc.Tests/MdocRecordTests.cs b/test/WalletFramework.MdocVc.Tests/MdocRecordTests.cs deleted file mode 100644 index 183da78d..00000000 --- a/test/WalletFramework.MdocVc.Tests/MdocRecordTests.cs +++ /dev/null @@ -1,39 +0,0 @@ -// TODO: Fix mdoc sample with device key -// using FluentAssertions; -// using Hyperledger.Aries.Storage; -// using LanguageExt; -// using Newtonsoft.Json.Linq; -// using WalletFramework.Core.Cryptography.Models; -// using WalletFramework.Core.Functional; -// using WalletFramework.MdocLib; -// using Xunit; -// -// namespace WalletFramework.MdocVc.Tests; -// -// public class MdocRecordTests -// { -// [Fact] -// public void Can_Encode_To_Json() -// { -// var encodedMdoc = MdocLib.Tests.Samples.EncodedMdoc; -// var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(new InvalidOperationException("Mdoc sample is corrupt")); -// var keyId = KeyId.CreateKeyId(); -// var record = mdoc.ToRecord(Option>.None, keyId); -// -// var sut = JObject.FromObject(record); -// -// sut[nameof(RecordBase.Id)]!.ToString().Should().Be(record.Id); -// sut[MdocRecordFun.MdocJsonKey]!.ToString().Should().Be(encodedMdoc); -// sut[MdocRecordFun.KeyIdJsonKey]!.ToString().Should().Be(keyId.ToString()); -// } -// -// [Fact] -// public void Can_Decode_From_Json() -// { -// var json = MdocVcSamples.MdocRecordJson; -// -// var sut = json.ToObject()!; -// -// sut.Mdoc.DocType.ToString().Should().Be(MdocLib.Tests.Samples.DocType); -// } -// } diff --git a/test/WalletFramework.MdocVc.Tests/MdocVcSamples.cs b/test/WalletFramework.MdocVc.Tests/MdocVcSamples.cs index 5c29c387..e9571992 100644 --- a/test/WalletFramework.MdocVc.Tests/MdocVcSamples.cs +++ b/test/WalletFramework.MdocVc.Tests/MdocVcSamples.cs @@ -6,7 +6,11 @@ public static class MdocVcSamples { public static JObject MdocRecordJson => new() { - ["Id"] = "5c75f511-8ebb-4f3a-9ef2-cc63eaa65cc0", - ["mdoc"] = "omdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGxpc3N1ZXJTaWduZWSiamlzc3VlckF1dGiEQ6EBJqEYIVkBYTCCAV0wggEEoAMCAQICBgGMkdnCGTAKBggqhkjOPQQDAjA2MTQwMgYDVQQDDCtKMUZ3SlA4N0M2LVFOX1dTSU9tSkFRYzZuNUNRX2JaZGFGSjVHRG5XMVJrMB4XDTIzMTIyMjE0MDY1NloXDTI0MTAxNzE0MDY1NlowNjE0MDIGA1UEAwwrSjFGd0pQODdDNi1RTl9XU0lPbUpBUWM2bjVDUV9iWmRhRko1R0RuVzFSazBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAKKVXm6CaWEcnMNWCpJETl3wqShCpfWNWDxYTho-MU4NlDrp8U8UiFZE_eKhVSLrtYZBKBNjcXpWaN_skxVDgwwCgYIKoZIzj0EAwIDRwAwRAIgZxY0nAXLxEZXi4zAruTW8SSpDbGv4EIZF03w5m6vk94CIFWs27FXUL2YJbnPZyWEMVpc10_Yun_sIFCsdCgmG49wWQHt2BhZAeilZ3ZlcnNpb25jMS4wb2RpZ2VzdEFsZ29yaXRobWdTSEEtMjU2bHZhbHVlRGlnZXN0c6Fxb3JnLmlzby4xODAxMy41LjGoAVggq5LwUJ4Jy8MzBmAR7O65W_4NixSl3Kkmn1psmuocCZcCWCC7sP7e-v42suDfOKC6dTMQoWpgDIbmwD59--YONHFnbgNYILY4GeGhkWGoTuzw9F916Py3l-un4eAX_Zfioy3O8RjoBFggEX-uX3dVHbW6aQh1IyJaoWZPknGzSfcflJaidasmgOsFWCAoO9XIxTfnwt7SfpORVvZzQFuFtIwnCmzC08s2JmtNHwZYIAVnMnACacLtBwxDCrvYUNCWY_GTTjfhxluHr-u3VVqBB1ggfAEdDf6xU-1yj5FxSG5hirqKK-6ONjImZAFtD852EUMIWCByNPYdiCSjGfBY_72Oo7_r4P53r0f1RbbGOkNauSeW8Gdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGx2YWxpZGl0eUluZm-jZnNpZ25lZMB0MjAyNC0wMS0xMlQwMDoxMDowNVppdmFsaWRGcm9twHQyMDI0LTAxLTEyVDAwOjEwOjA1Wmp2YWxpZFVudGlswHQyMDI1LTAxLTEyVDAwOjEwOjA1WlhAcXMRvT00XIWWPnfcUT_UH0jauS73QrnZqvrgh3ULI5RdZfOEg15V-glTVx_GAJPYJfXfr1wZ39NDFKOFXHxulmpuYW1lU3BhY2VzoXFvcmcuaXNvLjE4MDEzLjUuMYjYGFhbpGhkaWdlc3RJRAFmcmFuZG9tUHG55kyB7dP9e7fgHB5CmWxxZWxlbWVudElkZW50aWZpZXJqaXNzdWVfZGF0ZWxlbGVtZW50VmFsdWXZA-xqMjAyNC0wMS0xMtgYWFykaGRpZ2VzdElEAmZyYW5kb21QUcL8wVSWAXNqZYXe712cE3FlbGVtZW50SWRlbnRpZmllcmtleHBpcnlfZGF0ZWxlbGVtZW50VmFsdWXZA-xqMjAyNS0wMS0xMtgYWFqkaGRpZ2VzdElEA2ZyYW5kb21Q3LgYdsROkqsQwxAjmPR9wnFlbGVtZW50SWRlbnRpZmllcmtmYW1pbHlfbmFtZWxlbGVtZW50VmFsdWVrU2lsdmVyc3RvbmXYGFhSpGhkaWdlc3RJRARmcmFuZG9tUB7uRXveoCUB_jXjgL0riXRxZWxlbWVudElkZW50aWZpZXJqZ2l2ZW5fbmFtZWxlbGVtZW50VmFsdWVkSW5nYdgYWFukaGRpZ2VzdElEBWZyYW5kb21QyPuG9N0ftvZYxYVKGTBz9HFlbGVtZW50SWRlbnRpZmllcmpiaXJ0aF9kYXRlbGVsZW1lbnRWYWx1ZdkD7GoxOTkxLTExLTA22BhYVaRoZGlnZXN0SUQGZnJhbmRvbVAiZV6ZdFAMYYojfQcEpy3gcWVsZW1lbnRJZGVudGlmaWVyb2lzc3VpbmdfY291bnRyeWxlbGVtZW50VmFsdWViVVPYGFhbpGhkaWdlc3RJRAdmcmFuZG9tUG1s_4IFMcrUmse_xags6BBxZWxlbWVudElkZW50aWZpZXJvZG9jdW1lbnRfbnVtYmVybGVsZW1lbnRWYWx1ZWgxMjM0NTY3ONgYWKKkaGRpZ2VzdElECGZyYW5kb21QW0sDoPdZTLKbv3LQWtrqoHFlbGVtZW50SWRlbnRpZmllcnJkcml2aW5nX3ByaXZpbGVnZXNsZWxlbWVudFZhbHVlgaN1dmVoaWNsZV9jYXRlZ29yeV9jb2RlYUFqaXNzdWVfZGF0ZdkD7GoyMDIzLTAxLTAxa2V4cGlyeV9kYXRl2QPsajIwNDMtMDEtMDE" + ["Id"] = "4c77d70b-ce55-424d-a718-333a3febdd5b", + ["mdoc"] = "omdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGxpc3N1ZXJTaWduZWSiamlzc3VlckF1dGiEQ6EBJqEYIVkECzCCBAcwggLvoAMCAQICFC91o6_IowD4Ur1EK5mg4nwHU3MHMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJERTEPMA0GA1UECAwGSGVzc2VuMRowGAYDVQQHDBFGcmFua2Z1cnQgYW0gTWFpbjEVMBMGA1UECgwMVGVzdCBDb21wYW55MRIwEAYDVQQLDAlUZXN0IFVuaXQxDTALBgNVBAMMBFRlc3QxHDAaBgkqhkiG9w0BCQEWDVRlc3RAdGVzdC5jb20wHhcNMjUwODE0MDY0OTM1WhcNMjYwODE0MDY0OTM1WjCBkjELMAkGA1UEBhMCREUxDzANBgNVBAgMBkhlc3NlbjEaMBgGA1UEBwwRRnJhbmtmdXJ0IGFtIE1haW4xFTATBgNVBAoMDFRlc3QgQ29tcGFueTESMBAGA1UECwwJVGVzdCBVbml0MQ0wCwYDVQQDDARUZXN0MRwwGgYJKoZIhvcNAQkBFg1UZXN0QHRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkniO5UBYYy8EFbenFoCw9dzvaRH7Pp4RSLqzV5shg2R1KZJEj03FJ_1ECjcnA6pThrw4V0uwiixLY7bQ5HDV-C9xHxO5GfbScoaRCsrwtm3JucPqQaVc4CgGk---kyp-fomFDmSqOTVqJLrNKMniA5ohIAorS6urB-dKgF8q5AZ_xe_KTCe9qeZ7JDxu_JxMR-7G4P9Ktq0buuyiRhW6hKzLioGzVPGrw79KNYdIUQgdlJmiLzwkYjPrrm-faPLTrzbBRDl_gX2wxS7kVmy_mESFvKMgnX95ae_wKL6Safzbeh3fbgcrPvYXjF2ZyLRSp7AbrYphu_GxOrSR2S8JAwIDAQABo1MwUTAdBgNVHQ4EFgQUUp_qjf-pvURVP-cWUuB9T7TnEkowHwYDVR0jBBgwFoAUUp_qjf-pvURVP-cWUuB9T7TnEkowDwYDVR0TAQH_BAUwAwEB_zANBgkqhkiG9w0BAQsFAAOCAQEAiJyQJrlLJnUBJXWSgQ5oyomSgZFNMUVmDXnL_RT5HByGS4M3Xj-Es3XoFepZQJdYlM1uZx6WWriwioJ3X9RbnznQDnLdC-wU50gIZ1uhiRth_FRRwfgr1aHYzKZg5sL_aEc9B76TRUAUSU8VYWBcladV7SQRqOY5QC9gOptGJUfHp6yKMJ9Di0K6NGdswH_medX0z9v_auOdOCHzvnd_4Kp5YuwdNYRDMeV90GUnqRlvLZAC7PVDbDB2XzIkGY1HmIRuWRRMJES0y2R_EYpGa2viO7PxMmLgPwPaHdOqMav2ibxWchIbfKP1Nr6bGQCxImqN5ZvfBJfPq2vog5fdxlkCDNgYWQIHp2d2ZXJzaW9uYzEuMG9kaWdlc3RBbGdvcml0aG1nU0hBLTI1Nmdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGx2YWx1ZURpZ2VzdHOhcW9yZy5pc28uMTgwMTMuNS4xogBYIDCuG2Pl0G2jwUJm-lpS-Wjt5Vgo_hE70NVYLWM2zhPWAVggpazwAlF4cX7j-NBzDHaflc9yBw5zEyANj-jvqqSWb7BtZGV2aWNlS2V5SW5mb6FpZGV2aWNlS2V5pAECIAEhWCAg-QilggJwXlxnOIFYB0klBZSvnJUAu89zM6p_y6jdkCJYIGZBs-z8vNggFIGbvJ6gjzyMEEype9bNEGLip_9MyRMCbHZhbGlkaXR5SW5mb6Nmc2lnbmVkwHgYMjAyNS0wOC0xM1QxODoyNzo0Mi45MDNaaXZhbGlkRnJvbcB4GDIwMjUtMDgtMTNUMTg6Mjc6NDIuOTAzWmp2YWxpZFVudGlswHgYMjAzMC0wMS0zMFQxNTozODowMS41NjlaZnN0YXR1c6Frc3RhdHVzX2xpc3SiY2lkeBkZIGN1cml4XGh0dHBzOi8vdGVzdC5jb25uZWN0b3IubGlzc2kuaW8vc3RhdHVzLWxpc3RzP3JlZ2lzdHJ5SWQ9NzcxOTZhMmMtNWZiMy00MmYzLTliZTAtMTkxNGNmOWQ4NTc4WECH6H12ua6wvdEY4Wb0zz0TA0Q9HOe0esZM7u3liFeZ784p_JCQh8JGSY9JzSB_G3P-VD6uCUF4Gz22FNkMhEpxam5hbWVTcGFjZXOhcW9yZy5pc28uMTgwMTMuNS4xgtgYWFKkaGRpZ2VzdElEAGZyYW5kb21Q4Ejotgk9siP1xWRe2w_YXnFlbGVtZW50SWRlbnRpZmllcmpnaXZlbl9uYW1lbGVsZW1lbnRWYWx1ZWRKb2hu2BhYUqRoZGlnZXN0SUQBZnJhbmRvbVAMjzFNR5dAQVKMrEtOdO5wcWVsZW1lbnRJZGVudGlmaWVya2ZhbWlseV9uYW1lbGVsZW1lbnRWYWx1ZWNEb2U", + ["keyId"] = "dd68c2a7-e3b7-447a-94a2-24a2e9cd8538", + ["credentialSetId"] = "fb3606b2-2853-4c3a-b7fb-cf86ceff8d79", + ["credentialState"] = "Active", + ["oneTimeUse"] = false }; } diff --git a/test/WalletFramework.MdocVc.Tests/WalletFramework.MdocVc.Tests.csproj b/test/WalletFramework.MdocVc.Tests/WalletFramework.MdocVc.Tests.csproj index 32590627..910e6258 100644 --- a/test/WalletFramework.MdocVc.Tests/WalletFramework.MdocVc.Tests.csproj +++ b/test/WalletFramework.MdocVc.Tests/WalletFramework.MdocVc.Tests.csproj @@ -15,10 +15,15 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/AuthFlow/AuthFlowSessionRecordTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/AuthFlow/AuthFlowSessionRecordTests.cs deleted file mode 100644 index 6d3e5ba6..00000000 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/AuthFlow/AuthFlowSessionRecordTests.cs +++ /dev/null @@ -1,79 +0,0 @@ -using FluentAssertions; -using Hyperledger.Aries.Storage; -using LanguageExt; -using Newtonsoft.Json.Linq; -using WalletFramework.Core.Functional; -using WalletFramework.Core.Uri; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; -using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Records; -using WalletFramework.Oid4Vc.Oid4Vci.Authorization.Models; -using WalletFramework.Oid4Vc.Oid4Vci.CredOffer.Models; -using WalletFramework.Oid4Vc.Tests.Oid4Vci.AuthFlow.Samples; -using WalletFramework.Oid4Vc.Tests.Oid4Vci.Issuer.Samples; - -namespace WalletFramework.Oid4Vc.Tests.Oid4Vci.AuthFlow; - -public class AuthFlowSessionRecordTests -{ - [Fact] - public void Can_Encode_To_Json() - { - // Arrange - var clientOptions = new ClientOptions - { - ClientId = "i can write anything", - WalletIssuer = "i can write anything", - RedirectUri = "i can write anything" - }; - - var issuerMetadata = IssuerMetadataSample.DecodedDraft14AndLower; - - var authorizationServerMetadata = new AuthorizationServerMetadata - { - Issuer = "i can write anything", - TokenEndpoint = "i can write anything", - JwksUri = "i can write anything", - AuthorizationEndpoint = "i can write anything", - ResponseTypesSupported = new[] { "i can write anything" }, - }; - - var credentialConfigurationId = CredentialConfigurationId - .ValidCredentialConfigurationId(IssuerMetadataSample.MdocConfigurationId.ToString()) - .UnwrapOrThrow(new InvalidOperationException()); - - var authorizationData = new AuthorizationData( - clientOptions, - issuerMetadata, - authorizationServerMetadata, - Option.None, - new List { credentialConfigurationId }); - - var authorizationCodeParameters = new AuthorizationCodeParameters("hello", "world"); - - var sessionId = AuthFlowSessionState.CreateAuthFlowSessionState(); - var record = new AuthFlowSessionRecord(authorizationData, authorizationCodeParameters, sessionId, 15); - - // Act - var recordSut = JObject.FromObject(record); - var tagsSut = JObject.FromObject(record.Tags); - - // Assert - recordSut[nameof(RecordBase.Id)]!.ToString().Should().Be(record.Id); - tagsSut[nameof(AuthFlowSessionRecord.AuthFlowSessionState)] = record.AuthFlowSessionState.ToString(); - } - - [Fact] - public void Can_Decode_From_Json() - { - // Arrange - var json = AuthFlowSamples.AuthFlowSessionRecordJson; - - // Act - var record = json.ToObject(); - - // Assert - record.Should().NotBeNull(); - record!.Id.Should().Be(json[nameof(RecordBase.Id)]!.ToString()); - record.AuthorizationData.IssuerMetadata.CredentialIssuer.ToString().Should().Be(IssuerMetadataSample.CredentialIssuer.ToStringWithoutTrail()); - } -} diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/AuthFlow/Samples/AuthFlowSamples.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/AuthFlow/Samples/AuthFlowSamples.cs index 225c86ff..e69de29b 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/AuthFlow/Samples/AuthFlowSamples.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/AuthFlow/Samples/AuthFlowSamples.cs @@ -1,43 +0,0 @@ -using Newtonsoft.Json.Linq; -using WalletFramework.Oid4Vc.Tests.Oid4Vci.Issuer.Samples; - -namespace WalletFramework.Oid4Vc.Tests.Oid4Vci.AuthFlow.Samples; - -public static class AuthFlowSamples -{ - public static JObject AuthFlowSessionRecordJson => new() - { - ["authorization_data"] = new JObject - { - ["credential_oauth_token"] = new JObject - { - ["access_token"] = "i can write anything" - }, - ["client_options"] = new JObject - { - ["ClientId"] = "https://test-issuer.com/redirect", - ["WalletIssuer"] = "i can write anything", - ["RedirectUri"] = "https://test-issuer.com/redirect" - }, - ["issuer_metadata"] = IssuerMetadataSample.EncodedAsJsonDraft14AndLower, - ["authorization_server_metadata"] = new JObject - { - ["issuer"] = "i can write anything", - ["token_endpoint"] = "i can write anything", - ["jwks_uri"] = "i can write anything", - ["authorization_endpoint"] = "i can write anything", - ["response_types_supported"] = new JArray("i can write anything"), - }, - ["credential_configuration_ids"] = new JArray("org.iso.18013.5.1.mDL") - }, - ["authorization_code_parameters"] = new JObject - { - ["Challenge"] = "hello", - ["CodeChallengeMethod"] = "S256", - ["Verifier"] = "world" - }, - ["RecordVersion"] = 1, - ["Id"] = "598e7661-95a8-4531-b707-3d256d3c1745", - ["spec_version"] = "15" - }; -} diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/MdocConfigurationTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/MdocConfigurationTests.cs index 51e09c4e..84a4e4ba 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/MdocConfigurationTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/MdocConfigurationTests.cs @@ -39,20 +39,6 @@ public void Can_Parse() sut.CryptographicCurvesSupported.Match( list => list.Should().Contain(MdocConfigurationSample.CryptoCurve), () => Assert.Fail("CryptographicCurvesSupported must be some")); - - sut.Claims.Match( - claims => - { - var dict = claims.Value[MdocConfigurationSample.NameSpace]; - dict[MdocConfigurationSample.GivenName].Display.Match( - list => - { - list.Should().Contain(MdocConfigurationSample.EnglishDisplay); - list.Should().Contain(MdocConfigurationSample.JapaneseDisplay); - }, - () => Assert.Fail("Display must be some")); - }, - () => Assert.Fail("Claims must be some")); }, _ => Assert.Fail("Must be valid") ); diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/Samples/MdocConfigurationSample.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/Samples/MdocConfigurationSample.cs index d3b19d82..f20f7487 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/Samples/MdocConfigurationSample.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/Mdoc/Samples/MdocConfigurationSample.cs @@ -51,29 +51,7 @@ public static class MdocConfigurationSample ["batch_size"] = BatchSize }, ["cryptographic_suites_supported"] = new JArray { CryptoSuite.ToString() }, - ["cryptographic_curves_supported"] = new JArray { CryptoCurve.ToString() }, - ["claims"] = new JObject - { - [NameSpace] = new JObject - { - [GivenName] = new JObject - { - ["display"] = new JArray - { - new JObject - { - ["name"] = EnglishName.ToString(), - ["locale"] = LocaleSample.English.ToString() - }, - new JObject - { - ["name"] = JapaneseName.ToString(), - ["locale"] = LocaleSample.Japanese.ToString() - } - } - } - } - } + ["cryptographic_curves_supported"] = new JArray { CryptoCurve.ToString() } }; public static NameSpace NameSpace => diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/SdJwt/Samples/SdJwtConfigurationSample.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/SdJwt/Samples/SdJwtConfigurationSample.cs index da5f29fa..ef16c9ce 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/SdJwt/Samples/SdJwtConfigurationSample.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredConfiguration/SdJwt/Samples/SdJwtConfigurationSample.cs @@ -19,285 +19,194 @@ public static class SdJwtConfigurationSample .OptionalScope("VerifiedEMailSdJwtVc") .ToNullable() ?? throw new InvalidOperationException(); - public static JObject ValidDraft15 => new() + public static JObject ValidSample => new() { ["format"] = Format.ToString(), ["scope"] = Scope.ToString(), ["cryptographic_binding_methods_supported"] = new JArray { "jwk" }, ["credential_signing_alg_values_supported"] = new JArray { "ES256" }, - ["display"] = new JArray + ["proof_types_supported"] = new JObject { - new JObject { - ["name"] = "Verified e-mail adress", - ["logo"] = new JObject + "jwt", new JObject { - ["uri"] = "https://test-issuer.com/credential-logo.png" - }, - ["background_color"] = "#12107c", - ["text_color"] = "#FFFFFF", - ["locale"] = "en-US" + ["proof_signing_alg_values_supported"] = new JArray { "ES256" } + } } }, - ["vct"] = Vct.ToString(), - ["claims"] = new JArray() + ["credential_metadata"] = new JObject { - new JObject - { - ["path"] = new JArray(){"given_name"}, - ["display"] = new JArray - { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Vorname" - }, - new JObject - { - ["locale"] = "en-US", - ["name"] = "Given name" - } - } - }, - new JObject + ["display"] = new JArray { - ["path"] = new JArray(){"family_name"}, - ["display"] = new JArray + new JObject { - new JObject + ["name"] = "Verified e-mail adress", + ["logo"] = new JObject { - ["locale"] = "de-DE", - ["name"] = "Nachname" + ["uri"] = "https://test-issuer.com/credential-logo.png" }, - new JObject - { - ["locale"] = "en-US", - ["name"] = "Surname" - } - } - }, - new JObject - { - ["path"] = new JArray(){"email"}, - ["display"] = new JArray - { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "E-Mail Adresse" - }, - new JObject - { - ["locale"] = "en-US", - ["name"] = "e-Mail address" - } + ["background_color"] = "#12107c", + ["text_color"] = "#FFFFFF", + ["locale"] = "en-US" } }, - new JObject + ["claims"] = new JArray() { - ["path"] = new JArray(){"address" }, - ["display"] = new JArray + new JObject { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Adresse" - }, - new JObject - { - ["locale"] = "en-US", - ["name"] = "Address" - } - } - }, - new JObject - { - ["path"] = new JArray(){"address", "street"}, - ["display"] = new JArray - { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Straße" - }, - new JObject - { - ["locale"] = "en-US", - ["name"] = "Street" - } - } - }, - new JObject - { - ["path"] = new JArray(){"address", "zip"}, - ["display"] = new JArray - { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Postleitzahl" - }, - new JObject + ["path"] = new JArray(){"given_name"}, + ["display"] = new JArray { - ["locale"] = "en-US", - ["name"] = "Zip Code" + new JObject + { + ["locale"] = "de-DE", + ["name"] = "Vorname" + }, + new JObject + { + ["locale"] = "en-US", + ["name"] = "Given name" + } } - } - }, - new JObject - { - ["path"] = new JArray(){"address", "zip", "building"}, - ["display"] = new JArray + }, + new JObject { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Gebäude" - }, - new JObject + ["path"] = new JArray(){"family_name"}, + ["display"] = new JArray { - ["locale"] = "en-US", - ["name"] = "Building" + new JObject + { + ["locale"] = "de-DE", + ["name"] = "Nachname" + }, + new JObject + { + ["locale"] = "en-US", + ["name"] = "Surname" + } } - } - } - } - }; - public static JObject ValidDraft14AndLower => new() - { - ["format"] = Format.ToString(), - ["scope"] = Scope.ToString(), - ["cryptographic_binding_methods_supported"] = new JArray { "jwk" }, - ["credential_signing_alg_values_supported"] = new JArray { "ES256" }, - ["display"] = new JArray - { - new JObject - { - ["name"] = "Verified e-mail adress", - ["logo"] = new JObject - { - ["uri"] = "https://test-issuer.com/credential-logo.png" }, - ["background_color"] = "#12107c", - ["text_color"] = "#FFFFFF", - ["locale"] = "en-US" - } - }, - ["vct"] = Vct.ToString(), - ["claims"] = new JObject - { - ["given_name"] = new JObject - { - ["display"] = new JArray + new JObject { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Vorname" - }, - new JObject + ["path"] = new JArray(){"email"}, + ["display"] = new JArray { - ["locale"] = "en-US", - ["name"] = "Given name" + new JObject + { + ["locale"] = "de-DE", + ["name"] = "E-Mail Adresse" + }, + new JObject + { + ["locale"] = "en-US", + ["name"] = "e-Mail address" + } } - } - }, - ["family_name"] = new JObject - { - ["display"] = new JArray + }, + new JObject { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Nachname" - }, - new JObject + ["path"] = new JArray(){"address" }, + ["display"] = new JArray { - ["locale"] = "en-US", - ["name"] = "Surname" + new JObject + { + ["locale"] = "de-DE", + ["name"] = "Adresse" + }, + new JObject + { + ["locale"] = "en-US", + ["name"] = "Address" + } } - } - }, - ["email"] = new JObject - { - ["display"] = new JArray + }, + new JObject { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "E-Mail Adresse" - }, - new JObject + ["path"] = new JArray(){"address", "street"}, + ["display"] = new JArray { - ["locale"] = "en-US", - ["name"] = "e-Mail address" + new JObject + { + ["locale"] = "de-DE", + ["name"] = "Straße" + }, + new JObject + { + ["locale"] = "en-US", + ["name"] = "Street" + } } - } - }, - ["address"] = new JObject - { - ["display"] = new JArray + }, + new JObject { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Adresse" - }, - new JObject + ["path"] = new JArray(){"address", "zip"}, + ["display"] = new JArray { - ["locale"] = "en-US", - ["name"] = "Address" + new JObject + { + ["locale"] = "de-DE", + ["name"] = "Postleitzahl" + }, + new JObject + { + ["locale"] = "en-US", + ["name"] = "Zip Code" + } } }, - ["street"] = new JObject + new JObject { + ["path"] = new JArray(){"address", "zip", "building"}, ["display"] = new JArray { new JObject { ["locale"] = "de-DE", - ["name"] = "Straße" + ["name"] = "Gebäude" }, new JObject { ["locale"] = "en-US", - ["name"] = "Street" + ["name"] = "Building" } } }, - ["zip"] = new JObject + new JObject { + ["path"] = new JArray(){"degrees"}, ["display"] = new JArray { new JObject { ["locale"] = "de-DE", - ["name"] = "Postleitzahl" + ["name"] = "Abschlüsse" }, new JObject { ["locale"] = "en-US", - ["name"] = "Zip Code" + ["name"] = "Degrees" } - }, - ["building"] = new JObject + } + }, + new JObject + { + ["path"] = new JArray(){"degrees", JValue.CreateNull(), "type"}, + ["display"] = new JArray { - ["display"] = new JArray + new JObject { - new JObject - { - ["locale"] = "de-DE", - ["name"] = "Gebäude" - }, - new JObject - { - ["locale"] = "en-US", - ["name"] = "Building" - } + ["locale"] = "de-DE", + ["name"] = "Typ" + }, + new JObject + { + ["locale"] = "en-US", + ["name"] = "Type" } } } } - } + }, + ["vct"] = Vct.ToString() }; } diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredOffer/CredentialOfferTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredOffer/CredentialOfferTests.cs index 24514f10..03887731 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredOffer/CredentialOfferTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/CredOffer/CredentialOfferTests.cs @@ -23,7 +23,7 @@ public void Can_Parse_From_Json() var ids = offer.CredentialConfigurationIds.Select(id => (string)id).ToList(); - ids.Length().Should().Be(2); + ids.Count.Should().Be(2); ids.Should().Contain(UniversityDegreeCredential); ids.Should().Contain(OrgIso1801351Mdl); diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/IssuerMetadataTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/IssuerMetadataTests.cs index f06f068f..8a730f81 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/IssuerMetadataTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/IssuerMetadataTests.cs @@ -11,10 +11,10 @@ namespace WalletFramework.Oid4Vc.Tests.Oid4Vci.Issuer; public class IssuerMetadataTests { [Fact] - public void Can_Decode_Draft14_From_Json() + public void Can_Decode_From_Json() { // Arrange - var sample = IssuerMetadataSample.EncodedAsJsonDraft14AndLower; + var sample = IssuerMetadataSample.EncodedAsJson; // Act ValidIssuerMetadata(sample).Match( @@ -44,18 +44,18 @@ public void Can_Decode_Draft14_From_Json() [Fact] public void Can_Encode_To_Json() { - var issuerMetadata = IssuerMetadataSample.DecodedDraft14AndLower; + var issuerMetadata = IssuerMetadataSample.Decoded; var sut = issuerMetadata.EncodeToJson(); - sut.Should().BeEquivalentTo(IssuerMetadataSample.EncodedAsJsonDraft14AndLower); + sut.Should().BeEquivalentTo(IssuerMetadataSample.EncodedAsJson); } [Fact] - public void Can_Decode_And_Encode_From_Json_Draft14() + public void Can_Decode_And_Encode_From_Json() { // Arrange - var sample = IssuerMetadataSample.EncodedAsJsonDraft14AndLower; + var sample = IssuerMetadataSample.EncodedAsJson; // Act ValidIssuerMetadata(sample).Match( @@ -67,22 +67,4 @@ public void Can_Decode_And_Encode_From_Json_Draft14() }, _ => Assert.Fail("IssuerMetadata must be valid")); } - - [Fact] - public void Can_Decode_And_Encode_ClaimMetadata_From_Json_Draft15() - { - // Arrange - var sampleDraft15 = IssuerMetadataSample.EncodedAsJsonDraft15; - - // Act - ValidIssuerMetadata(sampleDraft15).Match( - // Assert - issuerMetadata => - { - ValidIssuerMetadata(issuerMetadata.EncodeToJson()).UnwrapOrThrow().CredentialConfigurationsSupported[IssuerMetadataSample.SdJwtConfigurationId].AsT0.Claims - .Should() - .BeEquivalentTo(issuerMetadata.CredentialConfigurationsSupported[IssuerMetadataSample.SdJwtConfigurationId].AsT0.Claims); - }, - _ => Assert.Fail("IssuerMetadata must be valid")); - } } diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/Samples/IssuerMetadataSample.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/Samples/IssuerMetadataSample.cs index fbcc23d1..eb58d087 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/Samples/IssuerMetadataSample.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vci/Issuer/Samples/IssuerMetadataSample.cs @@ -22,7 +22,7 @@ public static class IssuerMetadataSample .ValidCredentialConfigurationId(SdJwtConfigurationSample.Scope.ToString()) .UnwrapOrThrow(new InvalidOperationException()); - public static JObject EncodedAsJsonDraft14AndLower => new() + public static JObject EncodedAsJson => new() { ["credential_issuer"] = CredentialIssuer.ToStringWithoutTrail(), ["credential_endpoint"] = CredentialEndpoint.ToStringWithoutTrail(), @@ -50,7 +50,7 @@ public static class IssuerMetadataSample ["authorization_servers"] = new JArray { "https://test-issuer.com/authorizationserver" }, ["credential_configurations_supported"] = new JObject { - [SdJwtConfigurationId] = SdJwtConfigurationSample.ValidDraft14AndLower, + [SdJwtConfigurationId] = SdJwtConfigurationSample.ValidSample, [MdocConfigurationId] = MdocConfigurationSample.Valid }, ["batch_credential_issuance"] = new JObject @@ -59,43 +59,6 @@ public static class IssuerMetadataSample } }; - public static JObject EncodedAsJsonDraft15 => new() - { - ["credential_issuer"] = CredentialIssuer.ToStringWithoutTrail(), - ["credential_endpoint"] = CredentialEndpoint.ToStringWithoutTrail(), - ["display"] = new JArray - { - new JObject - { - ["name"] = "Test Company GmbH", - ["logo"] = new JObject - { - { "uri", "https://test-issuer.com/logo.png" } - }, - ["locale"] = "en-US" - }, - new JObject - { - ["name"] = "Test Company GmbH", - ["logo"] = new JObject - { - { "uri", "https://test-issuer.com/logo.png" } - }, - ["locale"] = "de-DE" - } - }, - ["authorization_servers"] = new JArray { "https://test-issuer.com/authorizationserver" }, - ["credential_configurations_supported"] = new JObject - { - [SdJwtConfigurationId] = SdJwtConfigurationSample.ValidDraft15, - [MdocConfigurationId] = MdocConfigurationSample.Valid - }, - ["batch_credential_issuance"] = new JObject - { - ["batch_size"] = 5 - } - }; - - public static IssuerMetadata DecodedDraft14AndLower => - IssuerMetadata.ValidIssuerMetadata(EncodedAsJsonDraft14AndLower).UnwrapOrThrow(new InvalidOperationException()); + public static IssuerMetadata Decoded => + IssuerMetadata.ValidIssuerMetadata(EncodedAsJson).UnwrapOrThrow(new InvalidOperationException()); } diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthRequest/X509SanDnsTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthRequest/X509SanDnsTests.cs index 8221c4ae..0cf94eea 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthRequest/X509SanDnsTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthRequest/X509SanDnsTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; using LanguageExt; -using Newtonsoft.Json.Linq; using WalletFramework.Core.Functional; using WalletFramework.Oid4Vc.Oid4Vp.Models; using static WalletFramework.Oid4Vc.Tests.Oid4Vp.AuthRequest.Samples.AuthRequestSamples; diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponseTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponseTests.cs index e6f18f8f..56c00262 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponseTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/AuthResponse/Encryption/EncryptedAuthorizationResponseTests.cs @@ -21,7 +21,7 @@ public void Can_Encrypt_With_Mdoc() Option.Some(["A256GCM"]), mdocNonce); - sut.Jwe.Length().Should().Be(AuthResponseEncryptionSamples.ValidMdocJwe.Length); + sut.Jwe.Length.Should().Be(AuthResponseEncryptionSamples.ValidMdocJwe.Length); } [Fact] diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/CredentialSets/CredentialSetTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/CredentialSets/CredentialDataSetTests.cs similarity index 99% rename from test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/CredentialSets/CredentialSetTests.cs rename to test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/CredentialSets/CredentialDataSetTests.cs index e8c6396d..39ee1848 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/CredentialSets/CredentialSetTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/CredentialSets/CredentialDataSetTests.cs @@ -7,7 +7,7 @@ namespace WalletFramework.Oid4Vc.Tests.Oid4Vp.Dcql.CredentialSets; -public class CredentialSetTests +public class CredentialDataSetTests { [Fact] public void Candidate_Query_Result_Can_Be_Built_Correctly_From_Dcql_Query_With_One_Credential_Set() diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlFindingCandidatesTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlFindingCandidatesTests.cs index a9507a91..767c110e 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlFindingCandidatesTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlFindingCandidatesTests.cs @@ -1,8 +1,15 @@ using FluentAssertions; +using LanguageExt; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.Core.Functional; +using WalletFramework.MdocLib; +using WalletFramework.MdocVc; using WalletFramework.Oid4Vc.Oid4Vp.Models; using WalletFramework.Oid4Vc.Tests.Oid4Vp.Dcql.Samples; using WalletFramework.Oid4Vc.Tests.Samples; using static WalletFramework.Oid4Vc.Oid4Vp.Dcql.DcqlFun; +using MdocSamples = WalletFramework.TestSamples.MdocSamples; namespace WalletFramework.Oid4Vc.Tests.Oid4Vp.Dcql; @@ -11,7 +18,7 @@ public class DcqlFindingCandidatesTests [Fact] public void Can_Process_Mdoc_Credential_Query() { - var mdoc = MdocSamples.MdocRecord; + var mdoc = GetMdocCredentialSample(); var query = DcqlSamples.GetMdocGivenNameQuery(); var sut = query.ProcessWith([mdoc]); @@ -47,7 +54,7 @@ from credential in set.Credentials [Fact] public void Can_Process_Mdoc_Credential_Query_With_Multiple_Claims() { - var mdoc = MdocSamples.MdocRecord; + var mdoc = GetMdocCredentialSample(); var query = DcqlSamples.GetMdocGivenNameAndFamilyNameQuery(); var sut = query.ProcessWith([mdoc]); @@ -84,8 +91,8 @@ from credential in set.Credentials [Fact] public void Can_Process_Mdoc_Credential_Query_With_Multiple_Credentials_In_One_Candidate() { - var mdoc1 = MdocSamples.MdocRecord; - var mdoc2 = MdocSamples.MdocRecord; + var mdoc1 = GetMdocCredentialSample(); + var mdoc2 = GetMdocCredentialSample(); var query = DcqlSamples.GetMdocGivenNameQuery(); var sut = query.ProcessWith([mdoc1, mdoc2]); @@ -121,7 +128,7 @@ from credential in set.Credentials [Fact] public void Can_Process_Query_That_Asks_For_SdJwt_And_Mdoc_At_The_Same_Time() { - var mdoc = MdocSamples.MdocRecord; + var mdoc = GetMdocCredentialSample(); var sdJwt = SdJwtSamples.GetIdCardCredential(); var query = DcqlSamples.GetMdocAndSdJwtFamilyNameQuery(); @@ -283,7 +290,7 @@ public void No_Match_Returns_None() [Fact] public void No_Match_Returns_None_For_Mdoc() { - var mdoc = MdocSamples.MdocRecord; + var mdoc = GetMdocCredentialSample(); var query = DcqlSamples.GetNoMatchErrorClaimPathQuery(); var sut = query.ProcessWith([mdoc]); @@ -293,4 +300,19 @@ public void No_Match_Returns_None_For_Mdoc() () => { } ); } + + private MdocCredential GetMdocCredentialSample() + { + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + var credentialState = CredentialState.Active; + var oneTimeUse = false; + + var mdocCredential = new MdocCredential(mdoc, credentialId, credentialSetId, keyId, credentialState, oneTimeUse, Option.None); + + return mdocCredential; + } } diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlParsingTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlParsingTests.cs index bb1e3a0e..4eb9db11 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlParsingTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/DcqlParsingTests.cs @@ -22,9 +22,9 @@ public void Can_Parse_Dcql_Query() .Should() .Be("https://credentials.example.com/identity_credential"); - dcqlQuery.CredentialQueries[0].Claims![0].Path.GetPathComponents().Length().Should().Be(1); - dcqlQuery.CredentialQueries[0].Claims![1].Path.GetPathComponents().Length().Should().Be(1); - dcqlQuery.CredentialQueries[0].Claims![2].Path.GetPathComponents().Length().Should().Be(2); + dcqlQuery.CredentialQueries[0].Claims![0].Path.GetPathComponents().Count.Should().Be(1); + dcqlQuery.CredentialQueries[0].Claims![1].Path.GetPathComponents().Count.Should().Be(1); + dcqlQuery.CredentialQueries[0].Claims![2].Path.GetPathComponents().Count.Should().Be(2); dcqlQuery.CredentialSetQueries!.Length.Should().Be(2); dcqlQuery.CredentialSetQueries[0].Purpose.Should().Contain(x => x.Name == "Identification"); diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/Samples/DcqlSamples.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/Samples/DcqlSamples.cs index 14925755..d83d61dd 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/Samples/DcqlSamples.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/Dcql/Samples/DcqlSamples.cs @@ -283,7 +283,7 @@ public static DcqlQuery GetMdocGivenNameAndFamilyNameQuery() ""doctype_value"": ""org.iso.18013.5.1.mDL"" }, ""claims"": [ - { ""path"": [""org.iso.18013.5.1"", ""document_number""] }, + { ""path"": [""org.iso.18013.5.1"", ""given_name""] }, { ""path"": [""org.iso.18013.5.1"", ""family_name""] } ] } diff --git a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/WalletMetadata/WalletMetadataTests.cs b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/WalletMetadata/WalletMetadataTests.cs index 1c40eb46..9000d279 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/WalletMetadata/WalletMetadataTests.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Oid4Vp/WalletMetadata/WalletMetadataTests.cs @@ -13,11 +13,11 @@ public void CreateDefault_ToJsonString_ShouldReturnValidJsonWithExpectedStructur var expectedJson = @"{ ""vp_formats_supported"": { ""vc+sd-jwt"": { - ""sd-jwt_alg_values"": [""ES256"", ""ES384"", ""ES512"", ""RS256""], + ""sd-jwt_alg_values"": [""ES256""], ""kb-jwt_alg_values"": [""ES256""] }, ""dc+sd-jwt"": { - ""sd-jwt_alg_values"": [""ES256"", ""ES384"", ""ES512"", ""RS256""], + ""sd-jwt_alg_values"": [""ES256""], ""kb-jwt_alg_values"": [""ES256""] }, ""mso_mdoc"": { diff --git a/test/WalletFramework.Oid4Vc.Tests/Samples/MdocSamples.cs b/test/WalletFramework.Oid4Vc.Tests/Samples/MdocSamples.cs deleted file mode 100644 index 80162523..00000000 --- a/test/WalletFramework.Oid4Vc.Tests/Samples/MdocSamples.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using WalletFramework.Core.Functional; -using WalletFramework.MdocLib; -using LanguageExt; -using WalletFramework.Core.Cryptography.Models; -using WalletFramework.Core.Credentials; -using WalletFramework.MdocVc; - -namespace WalletFramework.Oid4Vc.Tests.Samples; - -public static class MdocSamples -{ - public static string EncodedMdocBase64UrlStr = - "omdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGxpc3N1ZXJTaWduZWSiamlzc3VlckF1dGiEQ6EBJqEYIVkB8zCCAe8wggGVoAMCAQICFDxEFu7XhPO0E-SPVvB1q_pth-uEMAoGCCqGSM49BAMCMCMxFDASBgNVBAMMC3V0b3BpYSBpYWNhMQswCQYDVQQGEwJVUzAeFw0yMDEwMDEwMDAwMDBaFw0yMTEwMDEwMDAwMDBaMCExEjAQBgNVBAMMCXV0b3BpYSBkczELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASs56tzQOXZZIxacqmm9WdFx6rUNqA6Q-_qd7X6e4jwGX1X2Jg-GzfTpTn01Yg2XjjLv1uU1oxUe1vIcx3NLxRro4GoMIGlMB4GA1UdEgQXMBWBE2V4YW1wbGVAZXhhbXBsZS5jb20wHAYDVR0fBBUwEzARoA-gDYILZXhhbXBsZS5jb20wHQYDVR0OBBYEFBTikBemw1Yh_8emhre3LbBs0SNRMB8GA1UdIwQYMBaAFFT6I4OgTCjg2TB5ImHIDEiB0sALMA4GA1UdDwEB_wQEAwIHgDAVBgNVHSUBAf8ECzAJBgcogYxdBQECMAoGCCqGSM49BAMCA0gAMEUCIQCXcXq5AWdAyNe82qSUpiwFO73szhODwaynKtCNvATLsgIgO62FnBOmPG0a1n2BTUPiQlyvkNQiQiwEqO4DBMDTpo1ZA6LYGFkDnaZndmVyc2lvbmMxLjBvZGlnZXN0QWxnb3JpdGhtZ1NIQS0yNTZsdmFsdWVEaWdlc3RzonFvcmcuaXNvLjE4MDEzLjUuMa0AWCB1FnMztHtsK_uG7MwfQ4z1evBVNxrFXh41niDyVK3OvwFYIGflOdYTnr0TGu9EG0RWRd2DGys3WzkMpe9iebIF7UVxAlggM5Q3Ldt4BT821dhpeA5h7aMT1Eo5IJKtjgUnovv-Va4DWCAuNa08TlFLtnsanbUc505MubcUbkGsUtrJzoa4YT21VQRYIOpcMwS7fEqNy1HEwTtlJk-EVUE0E0IJPMp4bgWPrC1ZBVgg-uSH9ot6DoenSXdOVunh3DqOx7d-SQ0h8OHTR1Zhqh0GWCB9g-UHrnfbgV3k2AO4hVXQUR2JTIl0OfV3QFZBahx1MwdYIPBUmhRfHPdcvu_6iB1IV91DjWJ88yF0sXMcTDjhLKk2CFggtoyK_LKq98WBQR0od97xVb4usSGkK8m6W3MSN34Gj2YJWCALNYfR3QwqB6Nb-xINmaCr-131aGW7f6FcyLVqZt9uDApYIMmKFwzzbhGrtyTpinWlND36K27T3y7Pu47y7lXdQciBC1ggtX3QNngvexTGow-qqubM1QVM6IvfpRoBa6de2h7eqUgMWCBlH4c2sYSA_iUqAyJOoIe10QylSFFGxnx0rE7DES1MOnRvcmcuaXNvLjE4MDEzLjUuMS5VU6QAWCDYC4PSUXPEhMVkBhD_GjHJScHZNL9M9_GNUiOxXdTyHAFYIE2A4eLk-yRtl4lUJ85wALtZuyTIzQA-z5S_NbvSkX40AlggizMfO2hbyjcuhTUaJclISrevzfDSIzEFUR93jZjC9UQDWCDDQ68b0WkHFUORYaunNwLEdKv5krIMn7VcNqM26-Aah21kZXZpY2VLZXlJbmZvoWlkZXZpY2VLZXmkAQIgASFYIJYxPWxj4k4zcnQr_bGjO6LIl9zWirjHU-T71I3Ka3-aIlggH7Mmnt1BiFfeGzmk5KRLkvpITKpyLCKCiPAdDAOiw9ZnZG9jVHlwZXVvcmcuaXNvLjE4MDEzLjUuMS5tRExsdmFsaWRpdHlJbmZvo2ZzaWduZWTAdDIwMjAtMTAtMDFUMTM6MzA6MDJaaXZhbGlkRnJvbcB0MjAyMC0xMC0wMVQxMzozMDowMlpqdmFsaWRVbnRpbMB0MjAyMS0xMC0wMVQxMzozMDowMlpYQFnmQgXfHi9wjdbbCEeu15_HwCAdgPpVutyvLhvPWQLh5aYuSDIES4kK2FqlPxKRNHddczdU18t6QTdmrv8Tyy5qbmFtZVNwYWNlc6Fxb3JnLmlzby4xODAxMy41LjGG2BhYY6RoZGlnZXN0SUQAZnJhbmRvbVggh5hkWyDqIA4Z_6uskmJL7mrsY6zu3s-xuAB30iv8IOlxZWxlbWVudElkZW50aWZpZXJrZmFtaWx5X25hbWVsZWxlbWVudFZhbHVlY0RvZdgYWGykaGRpZ2VzdElEA2ZyYW5kb21YILI_Yn6JmccG3wwKTtmK10r5iK9hm0uweLiQWFU_RGFdcWVsZW1lbnRJZGVudGlmaWVyamlzc3VlX2RhdGVsZWxlbWVudFZhbHVl2QPsajIwMTktMTAtMjDYGFhtpGhkaWdlc3RJRARmcmFuZG9tWCDH_6MH5d6SHme6WHgJR4fogHrI57Wzky0s6A8A8-mrr3FlbGVtZW50SWRlbnRpZmllcmtleHBpcnlfZGF0ZWxlbGVtZW50VmFsdWXZA-xqMjAyNC0xMC0yMNgYWG2kaGRpZ2VzdElEB2ZyYW5kb21YICYFKkLliAVXqAbBRZrz-361BdN4FWYynQtgS4RbX55ocWVsZW1lbnRJZGVudGlmaWVyb2RvY3VtZW50X251bWJlcmxlbGVtZW50VmFsdWVpMTIzNDU2Nzg52BhZBHGkaGRpZ2VzdElECGZyYW5kb21YINCU2tdkouud61IQ6diZZD770dBpzDEdMpVRbKCwJEEtcWVsZW1lbnRJZGVudGlmaWVyaHBvcnRyYWl0bGVsZW1lbnRWYWx1ZVkEEv_Y_-AAEEpGSUYAAQEBAJAAkAAA_9sAQwATDQ4RDgwTEQ8RFRQTFx0wHx0aGh06KiwjMEU9SUdEPUNBTFZtXUxRaFJBQ1-CYGhxdXt8e0pchpCFd49teHt2_9sAQwEUFRUdGR04Hx84dk9DT3Z2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2_8AAEQgAGABkAwEiAAIRAQMRAf_EABsAAAMBAAMBAAAAAAAAAAAAAAAFBgQBAgMH_8QAMhAAAQMDAwIFAgMJAAAAAAAAAQIDBAAFEQYSIRMxFBVRYXEiQQeBoRY1QlJzkbLB8f_EABUBAQEAAAAAAAAAAAAAAAAAAAAB_8QAGhEBAQEAAwEAAAAAAAAAAAAAAAFBESExYf_aAAwDAQACEQMRAD8ApbveItojKcfWkrx9DQP1LPsP9156fvPncJcjodDa4Ubd-7PAOc4HrSvUen4y27jdHVLW70soT2SkgAZ9-1H4f_uV_wDrn_FNIV3mavCJzkS3296ctokKKDjt3xgHj3rdYtQR7025sQpl1rlaFHOB6g1JW5Mydf5runXBFBBKi6QQQT6YPf8AT1r100tLTN5jLQvx_RWSvdkcZBHzk0wvpq9rVJddEG3PSmWuVuhWAB68A8fOKd2e7x7xD8RH3J2natKu6TU3obp-T3Ddjv8AV8bf-14aGYVKg3WOVFKHUJRuxnBIUM0De86wi219LMdtMxf8e1zAT7ZwcmnFxuDFtgrlSSQhI7Dkk_YCoHVVnjWZcNmNuJUlRWtRyVHIr6E-qOmOPFloNng9XGP1phqZ_bcpCHXbS-iKs4S7u7_HGD_eqmM-iVHbfaOW3EhST7GovWEaWqKiQy8wq0IKem0yQMcYzwMfqe9MmtVQIFqgKVHfSh1shCGwFbdp24ySKYN-or6LGw050OupxRSE79uMDv2NJY2vPESWmfLtvUWE56-cZOP5a5vrKNSsQJMeZHjI52okqCVElQHYZ9Kx3N666ZucdSrk7Nbd5KF5wcHkYJOPkUnvZV5RXAORmiics9yiePt78Xf0-qgp3Yzj8qyafs3kkJcfr9fc4V7tm3HAGMZPpRRRSyTo5PjFybdcHoJXncEjPf7Agjj2rdYtORrMHFJWp55wbVLUMcegFFFAuf0UnrOmDcXojLvC2gkkEenccfOad2a0R7NE6EfcrJ3LWruo0UUGHUOm_PHmXPFdDpAjHT3Zz-YplcbcxcoSoskEoV9x3SfUUUU-CdGiFFCWHLs-qKlWQzt4HxzjPf7VTw4rUKK3HYTtbbGAKKKBdfdPxr2hBcUpp5HCXE88ehH3FYYmj0pmtybjPenqbxtSsYHHYHJOR7UUUgpaKKKD_9nYGFj_pGhkaWdlc3RJRAlmcmFuZG9tWCBFmfgb6qKyC9D_zJqgOm-YW--rP2vq_6QeY1TNsqss5HFlbGVtZW50SWRlbnRpZmllcnJkcml2aW5nX3ByaXZpbGVnZXNsZWxlbWVudFZhbHVlgqN1dmVoaWNsZV9jYXRlZ29yeV9jb2RlYUFqaXNzdWVfZGF0ZdkD7GoyMDE4LTA4LTA5a2V4cGlyeV9kYXRl2QPsajIwMjQtMTAtMjCjdXZlaGljbGVfY2F0ZWdvcnlfY29kZWFCamlzc3VlX2RhdGXZA-xqMjAxNy0wMi0yM2tleHBpcnlfZGF0ZdkD7GoyMDI0LTEwLTIw"; - - public static Mdoc Mdoc => Mdoc.ValidMdoc(EncodedMdocBase64UrlStr).UnwrapOrThrow(); - - public static MdocRecord MdocRecord => - new( - Mdoc, - Option>.None, - KeyId.CreateKeyId(), - CredentialSetId.CreateCredentialSetId(), - CredentialState.Active, - Option.None, - false - ); -} diff --git a/test/WalletFramework.Oid4Vc.Tests/Samples/SdJwtSamples.cs b/test/WalletFramework.Oid4Vc.Tests/Samples/SdJwtSamples.cs index 21f70cce..96c8c0b8 100644 --- a/test/WalletFramework.Oid4Vc.Tests/Samples/SdJwtSamples.cs +++ b/test/WalletFramework.Oid4Vc.Tests/Samples/SdJwtSamples.cs @@ -1,57 +1,58 @@ +using LanguageExt; using WalletFramework.Core.Credentials; using WalletFramework.Core.Cryptography.Models; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; -using WalletFramework.SdJwtVc.Models.Records; +using WalletFramework.SdJwtLib.Models; +using WalletFramework.SdJwtVc; namespace WalletFramework.Oid4Vc.Tests.Samples; public static class SdJwtSamples { - public static SdJwtRecord GetIdCardCredential() + public static SdJwtCredential GetIdCardCredential() { const string encodedSdJwt = "eyJraWQiOiJiZmFmYjkzMy1iNzQ4LTQ3ODYtODc1Ny0zYzg0ZWFlNmUzZGUiLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJfc2QiOlsiUVBEUFFCbEEzdk9QaU9qR0lRRXBOc1l5S2Zjd2M1T3dDUlV5eWY2QTlRbyIsIk9LMWJpZXUwR0RIZWVRc2lzRkxOcUdmX0Z4eW5HT0dTNHl5Q2dZeFVhTkEiLCJUSkJ4ajBGSmdTQlUxMzVDSDRacFJieTRfVG4tNWR4TFJBX0paRnNscXhjIiwiaFBjV0phVkRJdDlDZ1E3bWxzNmFSVFR6bHZ0NmlMYzlUWFRJZ2VuZDFWayIsIkNhZm9TdzRiMWdsV196ckdyN3lodFFyQ3RIYW51NG15MVBxTGtXQkx5aFkiXSwibmJmIjoxNzA2NTQyNjgxLCJ2Y3QiOiJJRC1DYXJkIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2U4MGMtMjE3LTExMS0xMDgtMTc0Lm5ncm9rLWZyZWUuYXBwIiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6Img2VUtiVXQ1SW4yTzVwUzUxYXRWaERuTDl0SGR4S3lkMTZXTG94R2dFQzQiLCJ5IjoiMDdIX05RcmlxRmxSb0JjVk5ZVW5aS2wwQ1A0U0NiN3RxU0NWWFNDTWh0ayJ9fSwiZXhwIjoxNzM4MjUxNDgxLCJpYXQiOjE3MTY5OTA0MDAsInN0YXR1cyI6eyJpZHgiOjYsInVyaSI6Imh0dHBzOi8vZTgwYy0yMTctMTExLTEwOC0xNzQubmdyb2stZnJlZS5hcHAvc3RhdHVzLWxpc3RzP3JlZ2lzdHJ5SWQ9YmQ1MDllMzYtNTQzNy00Zjg4LTkzYTUtNDEzNDA3ZjZiZDhmIn19.-3GEPOjEn4bopEGyy8ho_kFSfQVmkkZiFKMebtiZE6EsyRnunJtA46M_SwHQjmSm-73zIeRX7L7Rpszm8dkFhQ~WyJfSU1WWFVtc052bm9YTDR3NVRPSFpnIiwiYWRkcmVzcyIseyJzdHJlZXRfYWRkcmVzcyI6IjQyIE1hcmtldCBTdHJlZXQiLCJwb3N0YWxfY29kZSI6IjEyMzQ1In1d~WyJ3RzkzbExRRFBDUVgxTUtCYW5mVkVRIiwibGFzdF9uYW1lIiwiRG9lIl0~WyJFa1h0a0JHZXd2dkthRXlzTWhyVGJnIiwibmF0aW9uYWxpdGllcyIsWyJCcml0aXNoIiwiQmV0ZWxnZXVzaWFuIl1d~WyJzQlh2dVQxRHhaN0NrMTdJUXQzWWd3IiwiZmlyc3RfbmFtZSIsIkpvaG4iXQ~WyJoRWphWTA2WmFsNUZTS0pXSm9kUjZnIiwiZGVncmVlcyIsW3sidW5pdmVyc2l0eSI6IlVuaXZlcnNpdHkgb2YgQmV0ZWxnZXVzZSIsInR5cGUiOiJCYWNoZWxvciBvZiBTY2llbmNlIn0seyJ1bml2ZXJzaXR5IjoiVW5pdmVyc2l0eSBvZiBCZXRlbGdldXNlIiwidHlwZSI6Ik1hc3RlciBvZiBTY2llbmNlIn1dXQ~"; - var keyId = KeyId.CreateKeyId(); - - var record = new SdJwtRecord( - encodedSdJwt, - new Dictionary(), - [], - keyId, - CredentialSetId.CreateCredentialSetId() - ); - - return record; + var sdJwtDoc = new SdJwtDoc(encodedSdJwt); + var credential = new SdJwtCredential( + sdJwtDoc, + CredentialId.CreateCredentialId(), + CredentialSetId.CreateCredentialSetId(), + KeyId.CreateKeyId(), + CredentialState.Active, + false, + Option.None); + + return credential; } - public static SdJwtRecord GetIdCard2Credential() + public static SdJwtCredential GetIdCard2Credential() { const string encoded = "eyJ4NWMiOlsiTUlJQi9qQ0NBYVdnQXdJQkFnSVFYM0E0SDBYTlN4Q1Fhamg4Snp4dE16QUtCZ2dxaGtqT1BRUURBakFpTVNBd0hnWURWUVFERXhkMFpYTjBMbU52Ym01bFkzUnZjaTVzYVhOemFTNXBiekFlRncweU5ERXlNRGt4TnpNME1UTmFGdzB5TmpFeU1Ea3hOelEwTVROYU1DSXhJREFlQmdOVkJBTVRGM1JsYzNRdVkyOXVibVZqZEc5eUxteHBjM05wTG1sdk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRWlUMzhZREhadksveVlOYis3ZXUySzhHNmd2TVA0ZEMwQWFtcFpscjRtZ1RPKytlU3MxUkJvdUxYYzhEKzYyS2ZCS3dmN3g0MEd1SkdvN1ZWVDB5cTRLT0J2RENCdVRBT0JnTlZIUThCQWY4RUJBTUNCNEF3Q1FZRFZSMFRCQUl3QURBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUlLd1lCQlFVSEF3SXdQUVlEVlIwUkJEWXdOSUlaS2k1MFpYTjBMbU52Ym01bFkzUnZjaTVzYVhOemFTNXBiNElYZEdWemRDNWpiMjV1WldOMGIzSXViR2x6YzJrdWFXOHdId1lEVlIwakJCZ3dGb0FVTnVCbVljSG1HdnlGVWNwdTk5K0pFWndGbFJJd0hRWURWUjBPQkJZRUZEYmdabUhCNWhyOGhWSEtidmZmaVJHY0JaVVNNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRTZVZkNSSkZGOVFQeGRYVEZvOXZIY2FhVGRyY0N6QXNyQ2RtdG9KOGh0TEFpQnIwY2RJd0lIUE9XWkUrNWZWb1lIV3hrV1ZrdVVXbDMxTDdERmFkNlNwQXc9PSJdLCJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJfc2QiOlsiR1czaWxIZnIzWGxvc19RZEhxU0ZXN0tLbHAwN2ZSUVRMQnd5NVpoN01IcyIsIk1ucFFqWWNPcUl1LUh0QVpfb2dQNko5TXBReHJleVJLVWRWYjQxOGkwX2siLCJRYTBHT1NmREpobk5YMnQyNXIzWXRWclBaN2xiUm9hTnRKcUlWU0dkYlFBIiwiX3VEbXRJQV9tVjZLSlVTLXQtb25yZGZpc0ZRTHZFYUtEVW5EdlBGbzRqTSIsInVYT09sUE8xYUZhZjJJcFJwTHpWaTBKRi1yZUdvek9xLWxRTXNkdmg3Y0EiXSwibmJmIjoxNzA2NTQyNjgxLCJ2Y3QiOiJJRC1DYXJkLTIiLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vdGVzdC5pbyIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJlT2lTOUlidENSWUpRWmRwSUIzQWYxcGwtODhhTG9tbWk5WHRZYzJuUC1nIiwieSI6ImxldEVJNmFKbXp5cDJtWXk4Y090bTl6Ukk1QlJEMXJIQVFrV1lxTW5wcHMifX0sImV4cCI6MTg5NjAxNzg4MSwiaWF0IjoxNzQ2NzA5OTE5LCJzdGF0dXMiOnsiaWR4IjoiNDIyMSIsInVyaSI6Imh0dHBzOi8vdGVzdC5pby9zdGF0dXMtbGlzdHM_cmVnaXN0cnlJZD03NzE5NmEyYy01ZmIzLTQyZjMtOWJlMC0xOTE0Y2Y5ZDg1NzgifX0.GaugaQOpUrQhd_oAmg_y6uUm2uiAcgWPQXPtU9AlOoyOq-lLDb5rg2s55Rb5ziCWxZiAf7_ncDnPoWCV1PAcvA~WyJySDU2am52N2xhYjhhSGZiQ0s3N3lnIiwiZmlyc3RfbmFtZSIsIkpvaG4iXQ~WyIzY250clFDV1NLTXFUNHRiMlNHRXNnIiwibGFzdF9uYW1lIiwiRG9lIl0~WyJDUFd2V0dTRWdCeUwwN3dKS1Jwc1R3Iiwic3RyZWV0X2FkZHJlc3MiLCI0MiBNYXJrZXQgU3RyZWV0Il0~WyJXT2ExdkxrSzdCeTZaWEhjcFBNSWJRIiwicG9zdGFsX2NvZGUiLCIxMjM0NSJd~WyJhZnFEbHRvSmVnMmk2LWRfV2V6bkVBIiwiYWRkcmVzcyIseyJfc2QiOlsiTGk5UV9BM2EzcWxvZ0JXSHFMOWEtVjR6V2hDT3pEZjk2T2RheEp1T18xdyIsInVqTDY5bEtNY3FmN0x6OXJqRmhHY3ZlX3ZVYlhiUkJCeV83c1ZqNHVienciXX1d~WyJpT1RJSFh3dlFGenFKMmdGVy1IcWZnIix7InR5cGUiOiJCYWNoZWxvciBvZiBTY2llbmNlIiwidW5pdmVyc2l0eSI6IlVuaXZlcnNpdHkgb2YgQmV0ZWxnZXVzZSJ9XQ~WyJ5LU5oeURISC1CZW9Mc2tfQlpFcXFnIix7InR5cGUiOiJNYXN0ZXIgb2YgU2NpZW5jZSIsInVuaXZlcnNpdHkiOiJVbml2ZXJzaXR5IG9mIEJldGVsZ2V1c2UifV0~WyJHeGkxd05FUE16S1NLTHo1bUg5Rjh3IiwiZGVncmVlcyIsW3siLi4uIjoidEszcHBOaTlQVjItelB2Z2M0WFh0dGhUc1FSdmFFOUU5b1ZMcnRqeThDayJ9LHsiLi4uIjoicDJySGEzUmNCN2xOaTAtOEwydG9uZE1UTFBnalU2WkppV0lFZ3lya2wwRSJ9XV0~WyJfMm1nOC1xZkJYX1FiYTRWY3RDc3B3IiwibmF0aW9uYWxpdGllcyIsWyJCcml0aXNoIiwiQmV0ZWxnZXVzaWFuIl1d~"; - var keyId = KeyId.CreateKeyId(); - - var record = new SdJwtRecord( - encoded, - new Dictionary(), - [], - keyId, - CredentialSetId.CreateCredentialSetId() - ); - - return record; + var sdJwtDoc = new SdJwtDoc(encoded); + var credential = new SdJwtCredential( + sdJwtDoc, + CredentialId.CreateCredentialId(), + CredentialSetId.CreateCredentialSetId(), + KeyId.CreateKeyId(), + CredentialState.Active, + false, + Option.None); + + return credential; } - public static SdJwtRecord GetIdCard3Credential() + public static SdJwtCredential GetIdCard3Credential() { const string encodedSdJwt = "eyJraWQiOiJiZmFmYjkzMy1iNzQ4LTQ3ODYtODc1Ny0zYzg0ZWFlNmUzZGUiLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJfc2QiOlsiUVBEUFFCbEEzdk9QaU9qR0lRRXBOc1l5S2Zjd2M1T3dDUlV5eWY2QTlRbyIsIk9LMWJpZXUwR0RIZWVRc2lzRkxOcUdmX0Z4eW5HT0dTNHl5Q2dZeFVhTkEiLCJUSkJ4ajBGSmdTQlUxMzVDSDRacFJieTRfVG4tNWR4TFJBX0paRnNscXhjIiwiaFBjV0phVkRJdDlDZ1E3bWxzNmFSVFR6bHZ0NmlMYzlUWFRJZ2VuZDFWayIsIkNhZm9TdzRiMWdsV196ckdyN3lodFFyQ3RIYW51NG15MVBxTGtXQkx5aFkiXSwibmJmIjoxNzA2NTQyNjgxLCJ2Y3QiOiJJRC1DYXJkLTMiLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vZTgwYy0yMTctMTExLTEwOC0xNzQubmdyb2stZnJlZS5hcHAvIiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6Img2VUtiVXQ1SW4yTzVwUzUxYXRWaERuTDl0SGR4S3lkMTZXTG94R2dFQzQiLCJ5IjoiMDdIX05RcmlxRmxSb0JjVk5ZVW5aS2wwQ1A0U0NiN3RxU0NWWFNDTWh0ayJ9fSwiZXhwIjoxNzM4MjUxNDgxLCJpYXQiOjE3MTY5OTA0MDAsInN0YXR1cyI6eyJpZHgiOjYsInVyaSI6Imh0dHBzOi8vZTgwYy0yMTctMTExLTEwOC0xNzQubmdyb2stZnJlZS5hcHAvc3RhdHVzLWxpc3RzP3JlZ2lzdHJ5SWQ9YmQ1MDllMzYtNTQzNy00Zjg4LTkzYTUtNDEzNDA3ZjZiZDhmIn19.-3GEPOjEn4bopEGyy8ho_kFSfQVmkkZiFKMebtiZE6EsyRnunJtA46M_SwHQjmSm-73zIeRX7L7Rpszm8dkFhQ~WyJfSU1WWFVtc052bm9YTDR3NVRPSFpnIiwiYWRkcmVzcyIseyJzdHJlZXRfYWRkcmVzcyI6IjQyIE1hcmtldCBTdHJlZXQiLCJwb3N0YWxfY29kZSI6IjEyMzQ1In1d~WyJ3RzkzbExRRFBDUVgxTUtCYW5mVkVRIiwibGFzdF9uYW1lIiwiRG9lIl0~WyJFa1h0a0JHZXd2dkthRXlzTWhyVGJnIiwibmF0aW9uYWxpdGllcyIsWyJCcml0aXNoIiwiQmV0ZWxnZXVzaWFuIl1d~WyJzQlh2dVQxRHhaN0NrMTdJUXQzWWd3IiwiZmlyc3RfbmFtZSIsIkpvaG4iXQ~WyJoRWphWTA2WmFsNUZTS0pXSm9kUjZnIiwiZGVncmVlcyIsW3sidW5pdmVyc2l0eSI6IlVuaXZlcnNpdHkgb2YgQmV0ZWxnZXVzZSIsInR5cGUiOiJCYWNoZWxvciBvZiBTY2llbmNlIn0seyJ1bml2ZXJzaXR5IjoiVW5pdmVyc2l0eSBvZiBCZXRlbGdldXNlIiwidHlwZSI6Ik1hc3RlciBvZiBTY2llbmNlIn1dXQ~"; - var keyId = KeyId.CreateKeyId(); - - var record = new SdJwtRecord( - encodedSdJwt, - new Dictionary(), - [], - keyId, - CredentialSetId.CreateCredentialSetId() - ); - - return record; + var sdJwtDoc = new SdJwtDoc(encodedSdJwt); + var credential = new SdJwtCredential( + sdJwtDoc, + CredentialId.CreateCredentialId(), + CredentialSetId.CreateCredentialSetId(), + KeyId.CreateKeyId(), + CredentialState.Active, + false, + Option.None); + + return credential; } } diff --git a/test/WalletFramework.Oid4Vc.Tests/WalletFramework.Oid4Vc.Tests.csproj b/test/WalletFramework.Oid4Vc.Tests/WalletFramework.Oid4Vc.Tests.csproj index 1ff6c944..067655e9 100644 --- a/test/WalletFramework.Oid4Vc.Tests/WalletFramework.Oid4Vc.Tests.csproj +++ b/test/WalletFramework.Oid4Vc.Tests/WalletFramework.Oid4Vc.Tests.csproj @@ -33,10 +33,9 @@ - - + diff --git a/test/WalletFramework.SdJwtVc.Tests/SdJwtRecordTests.cs b/test/WalletFramework.SdJwtVc.Tests/SdJwtRecordTests.cs index 0ad81d55..e69de29b 100644 --- a/test/WalletFramework.SdJwtVc.Tests/SdJwtRecordTests.cs +++ b/test/WalletFramework.SdJwtVc.Tests/SdJwtRecordTests.cs @@ -1,27 +0,0 @@ -using FluentAssertions; -using WalletFramework.Core.Credentials; -using WalletFramework.Core.Cryptography.Models; -using WalletFramework.SdJwtVc.Models.Credential; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; -using WalletFramework.SdJwtVc.Models.Records; - -namespace WalletFramework.SdJwtVc.Tests; - -public class SdJwtRecordTests -{ - [Fact] - public void CanCreateSdJwtRecord() - { - var encodedSdJwt = Samples.EncodedSdJwt; - var keyId = KeyId.CreateKeyId(); - - var record = new SdJwtRecord( - encodedSdJwt, - new Dictionary(), - new List(), - keyId, - CredentialSetId.CreateCredentialSetId()); - - record.Claims.Count.Should().Be(10); - } -} diff --git a/test/WalletFramework.SdJwtVc.Tests/SdJwtVcHolderServiceTests.cs b/test/WalletFramework.SdJwtVc.Tests/SdJwtVcHolderServiceTests.cs index f1a55577..552c11e7 100644 --- a/test/WalletFramework.SdJwtVc.Tests/SdJwtVcHolderServiceTests.cs +++ b/test/WalletFramework.SdJwtVc.Tests/SdJwtVcHolderServiceTests.cs @@ -1,4 +1,3 @@ -using Hyperledger.Aries.Storage; using LanguageExt; using Moq; using WalletFramework.Core.Credentials; @@ -6,9 +5,6 @@ using WalletFramework.SdJwtLib.Models; using WalletFramework.SdJwtLib.Roles; using WalletFramework.SdJwtLib.Roles.Implementation; -using WalletFramework.SdJwtVc.Models.Credential; -using WalletFramework.SdJwtVc.Models.Credential.Attributes; -using WalletFramework.SdJwtVc.Models.Records; using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService; namespace WalletFramework.SdJwtVc.Tests; @@ -19,11 +15,10 @@ public class SdJwtVcHolderServiceTests public SdJwtVcHolderServiceTests() { - // Mock with moq IKestore and IWalletRecordService + // Mock with moq IHolder and ISdJwtSigner IHolder holder = new Holder(); var sdJwtSignerMock = new Mock().Object; - var walletRecordServiceMock = new Mock().Object; - _service = new SdJwtVcHolderService(holder, sdJwtSignerMock, walletRecordServiceMock); + _service = new SdJwtVcHolderService(holder, sdJwtSignerMock); } // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-08.html#appendix-A.3-4 @@ -32,13 +27,24 @@ public async Task Can_Create_Presentation_For_Example_4A() { const string issuedSdJwt = "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogInZjK3NkLWp3dCJ9.eyJfc2QiOiBbIjBIWm1uU0lQejMzN2tTV2U3QzM0bC0tODhnekppLWVCSjJWel9ISndBVGciLCAiOVpicGxDN1RkRVc3cWFsNkJCWmxNdHFKZG1lRU9pWGV2ZEpsb1hWSmRSUSIsICJJMDBmY0ZVb0RYQ3VjcDV5eTJ1anFQc3NEVkdhV05pVWxpTnpfYXdEMGdjIiwgIklFQllTSkdOaFhJbHJRbzU4eWtYbTJaeDN5bGw5WmxUdFRvUG8xN1FRaVkiLCAiTGFpNklVNmQ3R1FhZ1hSN0F2R1RyblhnU2xkM3o4RUlnX2Z2M2ZPWjFXZyIsICJodkRYaHdtR2NKUXNCQ0EyT3RqdUxBY3dBTXBEc2FVMG5rb3ZjS09xV05FIiwgImlrdXVyOFE0azhxM1ZjeUE3ZEMtbU5qWkJrUmVEVFUtQ0c0bmlURTdPVFUiLCAicXZ6TkxqMnZoOW80U0VYT2ZNaVlEdXZUeWtkc1dDTmcwd1RkbHIwQUVJTSIsICJ3elcxNWJoQ2t2a3N4VnZ1SjhSRjN4aThpNjRsbjFqb183NkJDMm9hMXVnIiwgInpPZUJYaHh2SVM0WnptUWNMbHhLdUVBT0dHQnlqT3FhMXoySW9WeF9ZRFEiXSwgImlzcyI6ICJodHRwczovL2lzc3Vlci5leGFtcGxlLmNvbSIsICJpYXQiOiAxNjgzMDAwMDAwLCAiZXhwIjogMTg4MzAwMDAwMCwgInZjdCI6ICJodHRwczovL2JtaS5idW5kLmV4YW1wbGUvY3JlZGVudGlhbC9waWQvMS4wIiwgImFnZV9lcXVhbF9vcl9vdmVyIjogeyJfc2QiOiBbIkZjOElfMDdMT2NnUHdyREpLUXlJR085N3dWc09wbE1Makh2UkM0UjQtV2ciLCAiWEx0TGphZFVXYzl6Tl85aE1KUm9xeTQ2VXNDS2IxSXNoWnV1cVVGS1NDQSIsICJhb0NDenNDN3A0cWhaSUFoX2lkUkNTQ2E2NDF1eWNuYzh6UGZOV3o4bngwIiwgImYxLVAwQTJkS1dhdnYxdUZuTVgyQTctRVh4dmhveHY1YUhodUVJTi1XNjQiLCAiazVoeTJyMDE4dnJzSmpvLVZqZDZnNnl0N0Fhb25Lb25uaXVKOXplbDNqbyIsICJxcDdaX0t5MVlpcDBzWWdETzN6VnVnMk1GdVBOakh4a3NCRG5KWjRhSS1jIl19LCAiX3NkX2FsZyI6ICJzaGEtMjU2IiwgImNuZiI6IHsiandrIjogeyJrdHkiOiAiRUMiLCAiY3J2IjogIlAtMjU2IiwgIngiOiAiVENBRVIxOVp2dTNPSEY0ajRXNHZmU1ZvSElQMUlMaWxEbHM3dkNlR2VtYyIsICJ5IjogIlp4amlXV2JaTVFHSFZXS1ZRNGhiU0lpcnNWZnVlY0NFNnQ0alQ5RjJIWlEifX19.jeF9GjGbjCr0NND0SbkV4HeSpsysixALFScJl4bYkIykXhF6cRtqni64_d7X6Ef8Rx80rfsgXe0H7TdiSoIJOw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiRXJpa2EiXQ~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIk11c3Rlcm1hbm4iXQ~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImJpcnRoZGF0ZSIsICIxOTYzLTA4LTEyIl0~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInNvdXJjZV9kb2N1bWVudF90eXBlIiwgImlkX2NhcmQiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInN0cmVldF9hZGRyZXNzIiwgIkhlaWRlc3RyYVx1MDBkZmUgMTciXQ~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImxvY2FsaXR5IiwgIktcdTAwZjZsbiJd~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgInBvc3RhbF9jb2RlIiwgIjUxMTQ3Il0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgImNvdW50cnkiLCAiREUiXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgImFkZHJlc3MiLCB7Il9zZCI6IFsiWEZjN3pYUG03enpWZE15d20yRXVCZmxrYTVISHF2ZjhVcF9zek5HcXZpZyIsICJiZDFFVnpnTm9wVWs0RVczX2VRMm4zX05VNGl1WE9IdjlYYkdITjNnMVRFIiwgImZfRlFZZ3ZRV3Z5VnFObklYc0FSbE55ZTdZR3A4RTc3Z1JBamFxLXd2bnciLCAidjRra2JfcFAxamx2VWJTanR5YzVicWNXeUEtaThYTHZoVllZN1pUMHRiMCJdfV0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIm5hdGlvbmFsaXRpZXMiLCBbIkRFIl1d~WyI1YlBzMUlxdVpOYTBoa2FGenp6Wk53IiwgImdlbmRlciIsICJmZW1hbGUiXQ~WyI1YTJXMF9OcmxFWnpmcW1rXzdQcS13IiwgImJpcnRoX2ZhbWlseV9uYW1lIiwgIkdhYmxlciJd~WyJ5MXNWVTV3ZGZKYWhWZGd3UGdTN1JRIiwgImxvY2FsaXR5IiwgIkJlcmxpbiJd~WyJIYlE0WDhzclZXM1FEeG5JSmRxeU9BIiwgInBsYWNlX29mX2JpcnRoIiwgeyJfc2QiOiBbIldwaEhvSUR5b1diQXBEQzR6YnV3UjQweGwweExoRENfY3Y0dHNTNzFyRUEiXSwgImNvdW50cnkiOiAiREUifV0~WyJDOUdTb3VqdmlKcXVFZ1lmb2pDYjFBIiwgImFsc29fa25vd25fYXMiLCAiU2Nod2VzdGVyIEFnbmVzIl0~WyJreDVrRjE3Vi14MEptd1V4OXZndnR3IiwgIjEyIiwgdHJ1ZV0~WyJIM28xdXN3UDc2MEZpMnllR2RWQ0VRIiwgIjE0IiwgdHJ1ZV0~WyJPQktsVFZsdkxnLUFkd3FZR2JQOFpBIiwgIjE2IiwgdHJ1ZV0~WyJNMEpiNTd0NDF1YnJrU3V5ckRUM3hBIiwgIjE4IiwgdHJ1ZV0~WyJEc210S05ncFY0ZEFIcGpyY2Fvc0F3IiwgIjIxIiwgdHJ1ZV0~WyJlSzVvNXBIZmd1cFBwbHRqMXFoQUp3IiwgIjY1IiwgZmFsc2Vd~"; // Arrange + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); var keyId = KeyId.CreateKeyId(); - var sdJwtRecord = new SdJwtRecord(issuedSdJwt, new Dictionary(), new List(), keyId, CredentialSetId.CreateCredentialSetId()); + + var sdJwtDoc = new SdJwtDoc(issuedSdJwt); + var sdJwtCredential = new SdJwtCredential( + sdJwtDoc, + credentialId, + credentialSetId, + keyId, + CredentialState.Active, + false, + Option.None); var claimsToDisclose = new[] { "given_name", "address.street_address", "nationalities[0]" }; // Act var result = await _service.CreatePresentation( - sdJwtRecord, + sdJwtCredential, claimsToDisclose, Option>.None, Option>.None, diff --git a/test/WalletFramework.SdJwtVc.Tests/WalletFramework.SdJwtVc.Tests.csproj b/test/WalletFramework.SdJwtVc.Tests/WalletFramework.SdJwtVc.Tests.csproj index 79789c97..897a8ea6 100644 --- a/test/WalletFramework.SdJwtVc.Tests/WalletFramework.SdJwtVc.Tests.csproj +++ b/test/WalletFramework.SdJwtVc.Tests/WalletFramework.SdJwtVc.Tests.csproj @@ -24,8 +24,6 @@ - - diff --git a/test/WalletFramework.Storage.Tests/AuthFlowSessionRecordCrudTests.cs b/test/WalletFramework.Storage.Tests/AuthFlowSessionRecordCrudTests.cs new file mode 100644 index 00000000..73ba0bb8 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/AuthFlowSessionRecordCrudTests.cs @@ -0,0 +1,129 @@ +using FluentAssertions; +using LanguageExt; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Functional; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; +using WalletFramework.Oid4Vc.Oid4Vci.Authorization.Models; +using WalletFramework.Oid4Vc.Oid4Vci.CredOffer.Models; +using WalletFramework.Oid4Vc.Oid4Vci.Issuer.Models; +using WalletFramework.Storage.Database; + +namespace WalletFramework.Storage.Tests; + +public class AuthFlowSessionRecordCrudTests : IDisposable +{ + public AuthFlowSessionRecordCrudTests() => (_serviceProvider, _dbPath) = TestDbSetup.CreateServiceProvider(); + + private readonly ServiceProvider _serviceProvider; + + private readonly string _dbPath; + + [Fact] + public async Task Can_Delete_AuthFlowSessionRecord() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var session = CreateSampleSession(); + await repository.Add(session); + + await repository.Delete(session.AuthFlowSessionState); + var fetched = await repository.GetById(session.AuthFlowSessionState); + fetched.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task Can_Store_And_Retrieve_AuthFlowSessionRecord() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var session = CreateSampleSession(); + await repository.Add(session); + + var fetched = await repository.GetById(session.AuthFlowSessionState); + fetched.Match( + found => { found.AuthFlowSessionState.ToString().Should().Be(session.AuthFlowSessionState.ToString()); }, + () => throw new InvalidOperationException("Record should exist")); + } + + [Fact] + public async Task Can_Update_AuthFlowSessionRecord() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var session = CreateSampleSession(); + await repository.Add(session); + + var updated = session with { SpecVersion = Prelude.Some(42) }; + await repository.Update(updated); + + var fetched = await repository.GetById(updated.AuthFlowSessionState); + fetched.IsSome.Should().BeTrue(); + } + + public void Dispose() + { + TestDbSetup.Cleanup(_serviceProvider, _dbPath); + GC.SuppressFinalize(this); + } + + private static AuthFlowSession CreateSampleSession() + { + var clientOptions = new ClientOptions("client", "issuer", "https://redirect"); + + var sdJwtConfig = new JObject + { + { "format", "vc+sd-jwt" }, + { "vct", "com.example.vct" } + }; + + var credentialConfigsSupported = new JObject + { + { "example_config", sdJwtConfig } + }; + + var issuerMetadataJson = new JObject + { + { IssuerMetadataJsonExtensions.CredentialEndpointJsonKey, "https://issuer/credential" }, + { IssuerMetadataJsonExtensions.CredentialIssuerJsonKey, "https://issuer" }, + { IssuerMetadataJsonExtensions.CredentialConfigsSupportedJsonKey, credentialConfigsSupported } + }; + var issuerMetadata = IssuerMetadata.ValidIssuerMetadata(issuerMetadataJson).UnwrapOrThrow(); + + var authServer = new AuthorizationServerMetadata + { + Issuer = "https://as", + TokenEndpoint = "https://as/token", + JwksUri = "https://as/jwks", + AuthorizationEndpoint = "https://as/auth", + TokenEndpointAuthMethodsSupported = ["client_secret_post"], + TokenEndpointAuthSigningAlgValuesSupported = ["RS256"] + }; + + var authorizationData = new AuthorizationData( + clientOptions, + issuerMetadata, + authServer, + Option.None, + new List()); + + var state = AuthFlowSessionState.CreateAuthFlowSessionState(); + var session = new AuthFlowSession(state, authorizationData, + new AuthorizationCodeParameters("challenge", "verifier"), Option.None); + return session; + } +} diff --git a/test/WalletFramework.Storage.Tests/CompletedPresentationRecordCrudTests.cs b/test/WalletFramework.Storage.Tests/CompletedPresentationRecordCrudTests.cs new file mode 100644 index 00000000..95489c60 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/CompletedPresentationRecordCrudTests.cs @@ -0,0 +1,240 @@ +using System.Linq.Expressions; +using FluentAssertions; +using LanguageExt; +using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Core.Credentials; +using WalletFramework.Oid4Vc.Oid4Vp; +using WalletFramework.Oid4Vc.Oid4Vp.Models; +using WalletFramework.Oid4Vc.Oid4Vp.Persistence; +using WalletFramework.Storage.Database; + +namespace WalletFramework.Storage.Tests; + +public class CompletedPresentationRecordCrudTests : IDisposable +{ + public CompletedPresentationRecordCrudTests() => (_serviceProvider, _dbPath) = TestDbSetup.CreateServiceProvider(); + + private readonly ServiceProvider _serviceProvider; + + private readonly string _dbPath; + + [Fact] + public async Task Can_Store_And_Retrieve_CompletedPresentationRecord() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var presentation = CreateSamplePresentation(); + + await repository.Add(presentation); + var fetched = await repository.GetById(presentation.PresentationId); + + fetched.Match( + found => + { + found.PresentationId.Should().Be(presentation.PresentationId); + found.ClientId.Should().Be(presentation.ClientId); + found.PresentedCredentialSets.Count.Should().Be(presentation.PresentedCredentialSets.Count); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Update_CompletedPresentationRecord() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var presentation = CreateSamplePresentation(); + await repository.Add(presentation); + + var updated = presentation with { Name = Prelude.Some("Updated Name") }; + await repository.Update(updated); + + var fetched = await repository.GetById(presentation.PresentationId); + + fetched.Match( + found => + { + found.Name.Match( + Some: n => n.Should().Be("Updated Name"), + None: () => Assert.Fail("Name should have a value") + ); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Delete_CompletedPresentationRecord_By_Id() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var presentation = CreateSamplePresentation(); + await repository.Add(presentation); + + await repository.Delete(presentation.PresentationId); + var fetched = await repository.GetById(presentation.PresentationId); + + fetched.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task Can_Delete_CompletedPresentationRecord_By_Domain() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var presentation = CreateSamplePresentation(); + await repository.Add(presentation); + + await repository.Delete(presentation); + var fetched = await repository.GetById(presentation.PresentationId); + + fetched.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task Can_ListAll_CompletedPresentationRecords() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var p1 = CreateSamplePresentation(); + var p2 = CreateSamplePresentation(); + await repository.Add(p1); + await repository.Add(p2); + + var list = await repository.ListAll(); + + list.Match( + Some: items => + { + items.Count.Should().BeGreaterOrEqualTo(2); + items.Any(i => i.PresentationId == p1.PresentationId).Should().BeTrue(); + items.Any(i => i.PresentationId == p2.PresentationId).Should().BeTrue(); + }, + None: () => throw new InvalidOperationException("List should not be empty") + ); + } + + [Fact] + public async Task Can_Find_CompletedPresentationRecords_By_ClientId() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var clientId = Guid.NewGuid().ToString("N"); + var p1 = CreateSamplePresentation() with { ClientId = clientId }; + var p2 = CreateSamplePresentation() with { ClientId = clientId }; + var other = CreateSamplePresentation(); + + await repository.Add(p1); + await repository.Add(p2); + await repository.Add(other); + + var cfg = new FindCompletedPresentationsByClientId(clientId); + var result = await repository.Find(cfg); + + result.Match( + Some: items => + { + items.Count.Should().Be(2); + items.All(i => i.ClientId == clientId).Should().BeTrue(); + }, + None: () => throw new InvalidOperationException("Result should not be empty") + ); + } + + [Fact] + public async Task RecordConfiguration_Enforces_Unique_PresentationId() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var p1 = CreateSamplePresentation(); + var p2 = p1 with { ClientId = Guid.NewGuid().ToString() }; + + await repository.Add(p1); + + Func act = async () => await repository.Add(p2); + + await act.Should().ThrowAsync(); + } + + [Fact] + public void Record_Serialization_RoundTrip() + { + var presentation = CreateSamplePresentation(); + var record = new CompletedPresentationRecord(presentation); + var back = record.ToDomainModel(); + + back.PresentationId.Should().Be(presentation.PresentationId); + back.ClientId.Should().Be(presentation.ClientId); + back.PresentedCredentialSets.Count.Should().Be(presentation.PresentedCredentialSets.Count); + } + + public void Dispose() + { + TestDbSetup.Cleanup(_serviceProvider, _dbPath); + GC.SuppressFinalize(this); + } + + private static CompletedPresentation CreateSamplePresentation() + { + var presented = new PresentedCredentialSet + { + CredentialSetId = CredentialSetId.CreateCredentialSetId(), + SdJwtCredentialType = Option.None, + MdocCredentialType = Option.None, + PresentedClaims = new Dictionary + { + { "given_name", new PresentedClaim { Value = "Jane" } }, + { "family_name", new PresentedClaim { Value = "Doe" } } + } + }; + + var clientMetadata = Option.None; + var name = Option.None; + + return new CompletedPresentation( + Guid.NewGuid().ToString("N"), + Guid.NewGuid().ToString("N"), + [presented], + clientMetadata, + name, + DateTimeOffset.UtcNow); + } + + private sealed record FindCompletedPresentationsByClientId(string ClientId) + : ISearchConfig + { + public Expression> ToPredicate() + { + return record => record.ClientId == ClientId; + } + } +} diff --git a/test/WalletFramework.Storage.Tests/CredentialDataSetRecordCrudTests.cs b/test/WalletFramework.Storage.Tests/CredentialDataSetRecordCrudTests.cs new file mode 100644 index 00000000..bde57c43 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/CredentialDataSetRecordCrudTests.cs @@ -0,0 +1,97 @@ +using FluentAssertions; +using LanguageExt; +using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Functional; +using WalletFramework.Oid4Vc.CredentialSet.Models; +using WalletFramework.Oid4Vc.CredentialSet.Persistence; +using WalletFramework.SdJwtVc.Models; +using WalletFramework.Storage.Database; + +namespace WalletFramework.Storage.Tests; + +public class CredentialDataSetRecordCrudTests : IDisposable +{ + public CredentialDataSetRecordCrudTests() => (_serviceProvider, _dbPath) = TestDbSetup.CreateServiceProvider(); + + private readonly ServiceProvider _serviceProvider; + + private readonly string _dbPath; + + [Fact] + public async Task Can_Store_And_Retrieve_CredentialSetRecord2() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var setId = CredentialSetId.CreateCredentialSetId(); + var domain = new CredentialDataSet( + setId, + Vct.ValidVct("example.vct").ToOption(), + Option.None, + new Dictionary { { "key", "value" } }, + CredentialState.Active, + Option.None, + Option.None, + Option.None, + Option.None, + Option.None, + Option.None, + "https://issuer.example.com"); + + await repository.Add(domain); + + var fetched = await repository.GetById(setId); + + fetched.Match( + found => + { + found.CredentialSetId.Should().Be(setId); + found.SdJwtCredentialType.IsSome.Should().BeTrue(); + found.CredentialAttributes["key"].Should().Be("value"); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Delete_CredentialDataSetRecord_By_Domain() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var setId = CredentialSetId.CreateCredentialSetId(); + var domain = new CredentialDataSet( + setId, + Vct.ValidVct("example.vct").ToOption(), + Option.None, + new Dictionary { { "key", "value" } }, + CredentialState.Active, + Option.None, + Option.None, + Option.None, + Option.None, + Option.None, + Option.None, + "https://issuer.example.com"); + + await repository.Add(domain); + + await repository.Delete(domain); + + var fetched = await repository.GetById(setId); + fetched.IsNone.Should().BeTrue(); + } + + public void Dispose() + { + TestDbSetup.Cleanup(_serviceProvider, _dbPath); + GC.SuppressFinalize(this); + } +} diff --git a/test/WalletFramework.Storage.Tests/DatabaseCreationTests.cs b/test/WalletFramework.Storage.Tests/DatabaseCreationTests.cs new file mode 100644 index 00000000..7886e997 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/DatabaseCreationTests.cs @@ -0,0 +1,28 @@ +using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Storage.Database; +using WalletFramework.Storage.Database.DependencyInjection; +using WalletFramework.Storage.Unencrypted.DependencyInjection; +using WalletFramework.Storage.Tests.TestModels; + +namespace WalletFramework.Storage.Tests; + +public class DatabaseCreationTests +{ + [Fact] + public async Task Can_Create_Database() + { + var (provider, dbPath) = await TestDbSetup.CreateServiceProviderForSimpleTest(); + + await using (provider) + { + File.Exists(dbPath).Should().BeTrue(); + } + + // Clean up + if (File.Exists(dbPath)) + { + File.Delete(dbPath); + } + } +} diff --git a/test/WalletFramework.Storage.Tests/MdocCredentialRecordCrudTests.cs b/test/WalletFramework.Storage.Tests/MdocCredentialRecordCrudTests.cs new file mode 100644 index 00000000..6a0dda2d --- /dev/null +++ b/test/WalletFramework.Storage.Tests/MdocCredentialRecordCrudTests.cs @@ -0,0 +1,300 @@ +using FluentAssertions; +using LanguageExt; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.Core.Functional; +using WalletFramework.MdocLib; +using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; +using WalletFramework.Storage.Database; +using WalletFramework.TestSamples; + +namespace WalletFramework.Storage.Tests; + +public class MdocCredentialRecordCrudTests : IDisposable +{ + public MdocCredentialRecordCrudTests() => (_serviceProvider, _dbPath) = TestDbSetup.CreateServiceProvider(); + + private readonly ServiceProvider _serviceProvider; + + private readonly string _dbPath; + + [Fact] + public async Task Can_Store_And_Retrieve_MdocCredentialRecord() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + + var mdocCredential = mdoc.ToMdocCredential( + KeyId.CreateKeyId(), + CredentialSetId.CreateCredentialSetId(), + CredentialState.Active, + false, + Option.None, + CredentialId.CreateCredentialId()); + + // Act + await repository.Add(mdocCredential); + var fetched = await repository.GetById(mdocCredential.CredentialId); + + // Assert + fetched.Match( + found => + { + found.CredentialId.Should().Be(mdocCredential.CredentialId); + found.Mdoc.DocType.Should().Be(mdocCredential.Mdoc.DocType); + found.CredentialId.AsString().Should().Be(mdocCredential.CredentialId.AsString()); + found.CredentialSetId.AsString().Should().Be(mdocCredential.CredentialSetId.AsString()); + found.KeyId.AsString().Should().Be(mdocCredential.KeyId.AsString()); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Update_MdocCredentialRecord() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + + var initial = mdoc.ToMdocCredential( + keyId, + credentialSetId, + CredentialState.Active, + false, + Option.None, + credentialId); + + await repository.Add(initial); + + // Act + var updated = mdoc.ToMdocCredential( + keyId, + credentialSetId, + CredentialState.Revoked, + true, + Option.Some(DateTime.UtcNow.AddDays(1)), + credentialId); + + await repository.Update(updated); + + var fetched = await repository.GetById(credentialId); + + // Assert + fetched.Match( + found => + { + found.CredentialId.Should().Be(credentialId); + found.CredentialState.Should().Be(CredentialState.Revoked); + found.OneTimeUse.Should().BeTrue(); + found.ExpiresAt.IsSome.Should().BeTrue(); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Delete_MdocCredentialRecord() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + + var mdocCredential = mdoc.ToMdocCredential( + keyId, + credentialSetId, + CredentialState.Active, + false, + Option.None, + credentialId); + + await repository.Add(mdocCredential); + + // Act + // Delete by id + await repository.Delete(credentialId); + var fetched = await repository.GetById(credentialId); + + // Assert + fetched.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task Can_Delete_MdocCredentialRecord_By_Domain() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + + var mdocCredential = mdoc.ToMdocCredential( + keyId, + credentialSetId, + CredentialState.Active, + false, + Option.None, + credentialId); + + await repository.Add(mdocCredential); + + // Act: delete by domain instance + await repository.Delete(mdocCredential); + var fetched = await repository.GetById(credentialId); + + // Assert + fetched.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task Can_ListAll_MdocCredentialRecords() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + + var id1 = CredentialId.CreateCredentialId(); + var id2 = CredentialId.CreateCredentialId(); + + var csid = CredentialSetId.CreateCredentialSetId(); + var kid = KeyId.CreateKeyId(); + + var cred1 = mdoc.ToMdocCredential(kid, csid, CredentialState.Active, false, Option.None, id1); + var cred2 = mdoc.ToMdocCredential(kid, csid, CredentialState.Active, false, Option.None, id2); + + await repository.Add(cred1); + await repository.Add(cred2); + + // Act + var list = await repository.ListAll(); + + // Assert + list.Match( + Some: items => + { + items.Count.Should().BeGreaterOrEqualTo(2); + items.Any(c => c.CredentialId.Equals(id1)).Should().BeTrue(); + items.Any(c => c.CredentialId.Equals(id2)).Should().BeTrue(); + }, + None: () => throw new InvalidOperationException("List should not be empty") + ); + } + + [Fact] + public async Task Can_Find_MdocCredentialRecords_By_DocType() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + + var csid = CredentialSetId.CreateCredentialSetId(); + var kid = KeyId.CreateKeyId(); + + var cred1 = mdoc.ToMdocCredential(kid, csid, CredentialState.Active, false, Option.None, CredentialId.CreateCredentialId()); + var cred2 = mdoc.ToMdocCredential(kid, csid, CredentialState.Active, false, Option.None, CredentialId.CreateCredentialId()); + + await repository.Add(cred1); + await repository.Add(cred2); + + // Act + var cfg = new FindMdocCredentialsWithDocType { DocType = mdoc.DocType }; + var result = await repository.Find(cfg); + + // Assert + result.Match( + Some: items => + { + items.Count.Should().Be(2); + items.All(i => i.Mdoc.DocType.AsString() == mdoc.DocType.AsString()).Should().BeTrue(); + }, + None: () => throw new InvalidOperationException("Result should not be empty") + ); + } + + [Fact] + public async Task Can_Find_MdocCredentialRecords_By_NonExistent_DocType_Returns_Empty() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var encodedMdoc = MdocSamples.GetEncodedMdocSample(); + var mdoc = Mdoc.ValidMdoc(encodedMdoc).UnwrapOrThrow(); + + var csid = CredentialSetId.CreateCredentialSetId(); + var kid = KeyId.CreateKeyId(); + + var cred1 = mdoc.ToMdocCredential(kid, csid, CredentialState.Active, false, Option.None, CredentialId.CreateCredentialId()); + + await repository.Add(cred1); + + // Act - search for a non-existent DocType + var nonExistentDocType = DocType.ValidDoctype(new JValue("non.existent.doctype")).UnwrapOrThrow(); + var cfg = new FindMdocCredentialsWithDocType { DocType = nonExistentDocType }; + var result = await repository.Find(cfg); + + // Assert + result.Match( + Some: _ => + { + Assert.Fail("Result should be empty for non-existent DocType"); + }, + None: () => + { + } + ); + } + + public void Dispose() + { + TestDbSetup.Cleanup(_serviceProvider, _dbPath); + GC.SuppressFinalize(this); + } +} diff --git a/test/WalletFramework.Storage.Tests/SdJwtCredentialRecordCrudTests.cs b/test/WalletFramework.Storage.Tests/SdJwtCredentialRecordCrudTests.cs new file mode 100644 index 00000000..06306cd9 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/SdJwtCredentialRecordCrudTests.cs @@ -0,0 +1,103 @@ +using FluentAssertions; +using LanguageExt; +using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Core.Credentials; +using WalletFramework.Core.Cryptography.Models; +using WalletFramework.SdJwtLib.Models; +using WalletFramework.SdJwtVc; +using WalletFramework.Storage.Database; +using WalletFramework.SdJwtVc.Persistence; + +namespace WalletFramework.Storage.Tests; + +public class SdJwtCredentialRecordCrudTests : IDisposable +{ + public SdJwtCredentialRecordCrudTests() => (_serviceProvider, _dbPath) = TestDbSetup.CreateServiceProvider(); + + private readonly ServiceProvider _serviceProvider; + + private readonly string _dbPath; + + [Fact] + public async Task Can_Store_And_Retrieve_SdJwtCredentialRecord() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + + const string encoded = + "eyJraWQiOiJiZmFmYjkzMy1iNzQ4LTQ3ODYtODc1Ny0zYzg0ZWFlNmUzZGUiLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJfc2QiOlsiUVBEUFFCbEEzdk9QaU9qR0lRRXBOc1l5S2Zjd2M1T3dDUlV5eWY2QTlRbyIsIk9LMWJpZXUwR0RIZWVRc2lzRkxOcUdmX0Z4eW5HT0dTNHl5Q2dZeFVhTkEiLCJUSkJ4ajBGSmdTQlUxMzVDSDRacFJieTRfVG4tNWR4TFJBX0paRnNscXhjIiwiaFBjV0phVkRJdDlDZ1E3bWxzNmFSVFR6bHZ0NmlMYzlUWFRJZ2VuZDFWayIsIkNhZm9TdzRiMWdsV196ckdyN3lodFFyQ3RIYW51NG15MVBxTGtXQkx5aFkiXSwibmJmIjoxNzA2NTQyNjgxLCJ2Y3QiOiJJRC1DYXJkIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2U4MGMtMjE3LTExMS0xMDgtMTc0Lm5ncm9rLWZyZWUuYXBwIiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6Img2VUtiVXQ1SW4yTzVwUzUxYXRWaERuTDl0SGR4S3lkMTZXTG94R2dFQzQiLCJ5IjoiMDdIX05RcmlxRmxSb0JjVk5ZVW5aS2wwQ1A0U0NiN3RxU0NWWFNDTWh0ayJ9fSwiZXhwIjoxNzM4MjUxNDgxLCJpYXQiOjE3MTY5OTA0MDAsInN0YXR1cyI6eyJpZHgiOjYsInVyaSI6Imh0dHBzOi8vZTgwYy0yMTctMTExLTEwOC0xNzQubmdyb2stZnJlZS5hcHAvc3RhdHVzLWxpc3RzP3JlZ2lzdHJ5SWQ9YmQ1MDllMzYtNTQzNy00Zjg4LTkzYTUtNDEzNDA3ZjZiZDhmIn19.-3GEPOjEn4bopEGyy8ho_kFSfQVmkkZiFKMebtiZE6EsyRnunJtA46M_SwHQjmSm-73zIeRX7L7Rpszm8dkFhQ~WyJfSU1WWFVtc052bm9YTDR3NVRPSFpnIiwiYWRkcmVzcyIseyJzdHJlZXRfYWRkcmVzcyI6IjQyIE1hcmtldCBTdHJlZXQiLCJwb3N0YWxfY29kZSI6IjEyMzQ1In1d~WyJ3RzkzbExRRFBDUVgxTUtCYW5mVkVRIiwibGFzdF9uYW1lIiwiRG9lIl0~WyJFa1h0a0JHZXd2dkthRXlzTWhyVGJnIiwibmF0aW9uYWxpdGllcyIsWyJCcml0aXNoIiwiQmV0ZWxnZXVzaWFuIl1d~WyJzQlh2dVQxRHhaN0NrMTdJUXQzWWd3IiwiZmlyc3RfbmFtZSIsIkpvaG4iXQ~WyJoRWphWTA2WmFsNUZTS0pXSm9kUjZnIiwiZGVncmVlcyIsW3sidW5pdmVyc2l0eSI6IlVuaXZlcnNpdHkgb2YgQmV0ZWxnZXVzZSIsInR5cGUiOiJCYWNoZWxvciBvZiBTY2llbmNlIn0seyJ1bml2ZXJzaXR5IjoiVW5pdmVyc2l0eSBvZiBCZXRlbGdldXNlIiwidHlwZSI6Ik1hc3RlciBvZiBTY2llbmNlIn1dXQ~"; + + var sdJwtDoc = new SdJwtDoc(encoded); + var sdjwt = new SdJwtCredential( + sdJwtDoc, + credentialId, + credentialSetId, + keyId, + CredentialState.Active, + false, + Option.None); + + await repository.Add(sdjwt); + + var fetched = await repository.GetById(credentialId); + + fetched.Match( + found => + { + found.CredentialId.Should().Be(credentialId); + found.EncodedIssuerSignedJwt.Should().Be(sdJwtDoc.IssuerSignedJwt); + found.CredentialSetId.AsString().Should().Be(credentialSetId.AsString()); + found.KeyId.ToNullable()?.AsString().Should().Be(keyId.AsString()); + found.Disclosures.Should().BeEquivalentTo(sdjwt.Disclosures); + found.Claims.Should().BeEquivalentTo(sdjwt.Claims); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Delete_SdJwtCredentialRecord_By_Domain() + { + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider + .GetRequiredService>(); + + var credentialId = CredentialId.CreateCredentialId(); + var credentialSetId = CredentialSetId.CreateCredentialSetId(); + var keyId = KeyId.CreateKeyId(); + + const string encoded = + "eyJraWQiOiJiZmFmYjkzMy1iNzQ4LTQ3ODYtODc1Ny0zYzg0ZWFlNmUzZGUiLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJfc2QiOlsiUVBEUFFCbEEzdk9QaU9qR0lRRXBOc1l5S2Zjd2M1T3dDUlV5eWY2QTlRbyIsIk9LMWJpZXUwR0RIZWVRc2lzRkxOcUdmX0Z4eW5HT0dTNHl5Q2dZeFVhTkEiLCJUSkJ4ajBGSmdTQlUxMzVDSDRacFJieTRfVG4tNWR4TFJBX0paRnNscXhjIiwiaFBjV0phVkRJdDlDZ1E3bWxzNmFSVFR6bHZ0NmlMYzlUWFRJZ2VuZDFWayIsIkNhZm9TdzRiMWdsV196ckdyN3lodFFyQ3RIYW51NG15MVBxTGtXQkx5aFkiXSwibmJmIjoxNzA2NTQyNjgxLCJ2Y3QiOiJJRC1DYXJkIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2U4MGMtMjE3LTExMS0xMDgtMTc0Lm5ncm9rLWZyZWUuYXBwIiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6Img2VUtiVXQ1SW4yTzVwUzUxYXRWaERuTDl0SGR4S3lkMTZXTG94R2dFQzQiLCJ5IjoiMDdIX05RcmlxRmxSb0JjVk5ZVW5aS2wwQ1A0U0NiN3RxU0NWWFNDTWh0ayJ9fSwiZXhwIjoxNzM4MjUxNDgxLCJpYXQiOjE3MTY5OTA0MDAsInN0YXR1cyI6eyJpZHgiOjYsInVyaSI6Imh0dHBzOi8vZTgwYy0yMTctMTExLTEwOC0xNzQubmdyb2stZnJlZS5hcHAvc3RhdHVzLWxpc3RzP3JlZ2lzdHJ5SWQ9YmQ1MDllMzYtNTQzNy00Zjg4LTkzYTUtNDEzNDA3ZjZiZDhmIn19.-3GEPOjEn4bopEGyy8ho_kFSfQVmkkZiFKMebtiZE6EsyRnunJtA46M_SwHQjmSm-73zIeRX7L7Rpszm8dkFhQ~WyJfSU1WWFVtc052bm9YTDR3NVRPSFpnIiwiYWRkcmVzcyIseyJzdHJlZXRfYWRkcmVzcyI6IjQyIE1hcmtldCBTdHJlZXQiLCJwb3N0YWxfY29kZSI6IjEyMzQ1In1d~WyJ3RzkzbExRRFBDUVgxTUtCYW5mVkVRIiwibGFzdF9uYW1lIiwiRG9lIl0~WyJFa1h0a0JHZXd2dkthRXlzTWhyVGJnIiwibmF0aW9uYWxpdGllcyIsWyJCcml0aXNoIiwiQmV0ZWxnZXVzaWFuIl1d~WyJzQlh2dVQxRHhaN0NrMTdJUXQzWWd3IiwiZmlyc3RfbmFtZSIsIkpvaG4iXQ~WyJoRWphWTA2WmFsNUZTS0pXSm9kUjZnIiwiZGVncmVlcyIsW3sidW5pdmVyc2l0eSI6IlVuaXZlcnNpdHkgb2YgQmV0ZWxnZXVzZSIsInR5cGUiOiJCYWNoZWxvciBvZiBTY2llbmNlIn0seyJ1bml2ZXJzaXR5IjoiVW5pdmVyc2l0eSBvZiBCZXRlbGdldXNlIiwidHlwZSI6Ik1hc3RlciBvZiBTY2llbmNlIn1dXQ~"; + var sdJwtDoc = new SdJwtDoc(encoded); + var sdjwt = new SdJwtCredential( + sdJwtDoc, + credentialId, + credentialSetId, + keyId, + CredentialState.Active, + false, + Option.None); + + await repository.Add(sdjwt); + + await repository.Delete(sdjwt); + + var fetched = await repository.GetById(credentialId); + fetched.IsNone.Should().BeTrue(); + } + + public void Dispose() + { + TestDbSetup.Cleanup(_serviceProvider, _dbPath); + GC.SuppressFinalize(this); + } +} diff --git a/test/WalletFramework.Storage.Tests/TestDbSetup.cs b/test/WalletFramework.Storage.Tests/TestDbSetup.cs new file mode 100644 index 00000000..ba1faf64 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/TestDbSetup.cs @@ -0,0 +1,88 @@ +using Microsoft.Extensions.DependencyInjection; +using WalletFramework.Core.Credentials; +using WalletFramework.MdocVc; +using WalletFramework.MdocVc.Persistence; +using WalletFramework.Storage; +using WalletFramework.Storage.Database; +using WalletFramework.Storage.Database.DependencyInjection; +using WalletFramework.Storage.Tests.TestModels; +using WalletFramework.Storage.Unencrypted.DependencyInjection; +using WalletFramework.SdJwtVc; +using WalletFramework.SdJwtVc.Persistence; +using WalletFramework.Oid4Vc.CredentialSet.Models; +using WalletFramework.Oid4Vc.CredentialSet.Persistence; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models; +using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Persistence; +using WalletFramework.Oid4Vc.Oid4Vp.Persistence; +using WalletFramework.Oid4Vc.Oid4Vp; + +namespace WalletFramework.Storage.Tests; + +public static class TestDbSetup +{ + /// + /// Cleans up test database resources + /// + /// The service provider to dispose + /// The database file path to delete + public static void Cleanup(ServiceProvider? serviceProvider, string dbPath) + { + serviceProvider?.Dispose(); + if (File.Exists(dbPath)) + { + File.Delete(dbPath); + } + } + + /// + /// Creates a service provider with standard test database configuration + /// + /// Optional custom database path. If null, generates a temporary path. + /// A tuple containing the service provider and database path + public static (ServiceProvider ServiceProvider, string DbPath) CreateServiceProvider(string? dbPath = null) + { + Batteries_V2.Init(); + + dbPath ??= Path.Combine(Path.GetTempPath(), $"wf_storage_test_{Guid.NewGuid():N}.db"); + var connectionString = $"Data Source={dbPath}"; + + var services = new ServiceCollection(); + + services.AddUnencryptedSqliteProvider(); + services.ConfigureStorage(connectionString, + builder => + { + builder.AddRecord(); + builder.AddRecord(); + builder.AddRecord(); + builder.AddRecord(); + builder.AddRecord(); + builder.AddRecord(); + }); + + services.AddScoped, MdocCredentialRepository>(); + services.AddScoped, SdJwtCredentialRepository>(); + services.AddScoped, CredentialDataSetRepository>(); + services.AddScoped, CompletedPresentationRepository>(); + services.AddScoped, AuthFlowSessionRepository>(); + + var serviceProvider = services.BuildServiceProvider(); + return (serviceProvider, dbPath); + } + + /// + /// Creates a service provider for simple one-off test scenarios + /// + /// A tuple containing the service provider and database path + public static async Task<(ServiceProvider ServiceProvider, string DbPath)> CreateServiceProviderForSimpleTest() + { + var (serviceProvider, dbPath) = CreateServiceProvider(); + + await using var scope = serviceProvider.CreateAsyncScope(); + var databaseCreator = scope.ServiceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + return (serviceProvider, dbPath); + } +} diff --git a/test/WalletFramework.Storage.Tests/TestModels/TestRecord.cs b/test/WalletFramework.Storage.Tests/TestModels/TestRecord.cs new file mode 100644 index 00000000..292449fc --- /dev/null +++ b/test/WalletFramework.Storage.Tests/TestModels/TestRecord.cs @@ -0,0 +1,95 @@ +using WalletFramework.Storage.Records; + +namespace WalletFramework.Storage.Tests.TestModels; + +/// +/// Test record for verifying CRUD operations on BaseRecord implementations. +/// +public record TestRecord() : RecordBase(Guid.NewGuid()) +{ + /// + /// Gets the boolean flag for testing. + /// + public required bool IsActive { get; init; } + + /// + /// Gets the integer value for testing. + /// + public required int Value { get; init; } + + /// + /// Gets the description of the test record. + /// + public required string Description { get; init; } + + /// + /// Gets the name of the test record. + /// + public required string Name { get; init; } + + /// + /// Factory method to create a new TestRecord. + /// + /// The name of the record. + /// The description of the record. + /// The integer value. + /// The boolean flag. + /// A new TestRecord instance. + public static TestRecord Create(string name, string description, int value, bool isActive) + { + var now = DateTimeOffset.UtcNow; + return new TestRecord + { + Name = name, + Description = description, + Value = value, + IsActive = isActive, + CreatedAt = now, + UpdatedAt = now, + RecordId = Guid.NewGuid() + }; + } + + /// + /// Factory method to create a TestRecord with specific Id and timestamps. + /// + /// The record identifier. + /// The name of the record. + /// The description of the record. + /// The integer value. + /// The boolean flag. + /// The creation timestamp. + /// The update timestamp. + /// A new TestRecord instance. + public static TestRecord Create(string id, string name, string description, int value, bool isActive, + DateTimeOffset createdAt, DateTimeOffset updatedAt) => + new() + { + RecordId = Guid.Parse(id), + Name = name, + Description = description, + Value = value, + IsActive = isActive, + CreatedAt = createdAt, + UpdatedAt = updatedAt + }; + + /// + /// Creates a copy of this record with updated properties. + /// + /// The new name (optional). + /// The new description (optional). + /// The new value (optional). + /// The new active flag (optional). + /// A new TestRecord instance with updated properties. + public TestRecord Update(string? name = null, string? description = null, int? value = null, + bool? isActive = null) => + this with + { + Name = name ?? Name, + Description = description ?? Description, + Value = value ?? Value, + IsActive = isActive ?? IsActive, + UpdatedAt = DateTimeOffset.UtcNow + }; +} diff --git a/test/WalletFramework.Storage.Tests/TestModels/TestRecordConfiguration.cs b/test/WalletFramework.Storage.Tests/TestModels/TestRecordConfiguration.cs new file mode 100644 index 00000000..7a65aa24 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/TestModels/TestRecordConfiguration.cs @@ -0,0 +1,32 @@ +using LanguageExt; +using Microsoft.EntityFrameworkCore; +using WalletFramework.Storage.Records; + +namespace WalletFramework.Storage.Tests.TestModels; + +/// +/// Entity Framework configuration for TestRecord. +/// +public record TestRecordConfiguration : IRecordConfiguration +{ + public Unit Configure(ModelBuilder modelBuilder) + { + var entity = modelBuilder.Entity(); + + entity.Property(r => r.Name) + .IsRequired() + .HasMaxLength(100); + + entity.Property(r => r.Description) + .IsRequired() + .HasMaxLength(500); + + entity.Property(r => r.Value) + .IsRequired(); + + entity.Property(r => r.IsActive) + .IsRequired(); + + return Unit.Default; + } +} diff --git a/test/WalletFramework.Storage.Tests/TestRecordCrudTests.cs b/test/WalletFramework.Storage.Tests/TestRecordCrudTests.cs new file mode 100644 index 00000000..af904a72 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/TestRecordCrudTests.cs @@ -0,0 +1,453 @@ +using FluentAssertions; +using LanguageExt; +using Microsoft.Extensions.DependencyInjection; +using System.Text.Json; +using WalletFramework.Core.Functional; +using WalletFramework.Storage.Database; +using WalletFramework.Storage.Repositories; +using WalletFramework.Storage.Tests.TestModels; + +namespace WalletFramework.Storage.Tests; + +public class TestRecordCrudTests : IDisposable +{ + public TestRecordCrudTests() + { + (_serviceProvider, _dbPath) = TestDbSetup.CreateServiceProvider(); + } + + private readonly ServiceProvider _serviceProvider; + + private readonly string _dbPath; + + [Fact] + public async Task Add_Should_Successfully_Create_Record() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test Name", "Test Description", 42, true); + + // Act + var result = await repository.Add(testRecord); + + // Assert + result.Should().Be(Unit.Default); + + var retrieved = await repository.GetById(testRecord.RecordId); + retrieved.IsSome.Should().BeTrue(); + + var record = retrieved.IfNone(() => throw new InvalidOperationException("Record should exist")); + record.Name.Should().Be("Test Name"); + record.Description.Should().Be("Test Description"); + record.Value.Should().Be(42); + record.IsActive.Should().BeTrue(); + record.RecordId.Should().Be(testRecord.RecordId); + } + + public void Dispose() + { + TestDbSetup.Cleanup(_serviceProvider, _dbPath); + } + + [Fact] + public async Task Find_Should_Return_Matching_Records() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var record1 = TestRecord.Create("Active Record", "Description 1", 10, true); + var record2 = TestRecord.Create("Inactive Record", "Description 2", 20, false); + var record3 = TestRecord.Create("Another Active", "Description 3", 30, true); + + await repository.Add(record1); + await repository.Add(record2); + await repository.Add(record3); + + // Act + var activeRecords = (await repository.Find(r => r.IsActive)).UnwrapOrThrow(); + var recordsWithValue20 = (await repository.Find(r => r.Value == 20)).UnwrapOrThrow(); + + // Assert + activeRecords.Should().HaveCount(2); + activeRecords.Should().Contain(r => r.RecordId == record1.RecordId); + activeRecords.Should().Contain(r => r.RecordId == record3.RecordId); + + recordsWithValue20.Should().HaveCount(1); + recordsWithValue20.Should().Contain(r => r.RecordId == record2.RecordId); + } + + [Fact] + public async Task GetById_Should_Return_None_When_Record_Does_Not_Exist() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var nonExistentId = Guid.NewGuid(); + + // Act + var result = await repository.GetById(nonExistentId); + + // Assert + result.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task GetById_Should_Return_Record_When_Exists() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test Name", "Test Description", 42, true); + await repository.Add(testRecord); + + // Act + var result = await repository.GetById(testRecord.RecordId); + + // Assert + result.IsSome.Should().BeTrue(); + var record = result.IfNone(() => throw new InvalidOperationException("Record should exist")); + record.RecordId.Should().Be(testRecord.RecordId); + record.Name.Should().Be("Test Name"); + } + + [Fact] + public async Task ListAll_Should_Return_All_Records() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + var record1 = TestRecord.Create("Record 1", "Description 1", 10, true); + var record2 = TestRecord.Create("Record 2", "Description 2", 20, false); + var record3 = TestRecord.Create("Record 3", "Description 3", 30, true); + + await repository.Add(record1); + await repository.Add(record2); + await repository.Add(record3); + + // Act + var allRecords = (await repository.ListAll()).UnwrapOrThrow(); + + // Assert + allRecords.Should().HaveCount(3); + allRecords.Should().Contain(r => r.RecordId == record1.RecordId); + allRecords.Should().Contain(r => r.RecordId == record2.RecordId); + allRecords.Should().Contain(r => r.RecordId == record3.RecordId); + } + + [Fact] + public async Task Multiple_Operations_Should_Work_Together() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + + // Act & Assert - Create multiple records + var record1 = TestRecord.Create("Record 1", "First record", 1, true); + var record2 = TestRecord.Create("Record 2", "Second record", 2, false); + var record3 = TestRecord.Create("Record 3", "Third record", 3, true); + + await repository.Add(record1); + await repository.Add(record2); + await repository.Add(record3); + + var allRecords = (await repository.ListAll()).UnwrapOrThrow(); + allRecords.Should().HaveCount(3); + + // Update one record + var updatedRecord2 = record2.Update(isActive: true, value: 22); + await repository.Update(updatedRecord2); + + var activeRecords = (await repository.Find(r => r.IsActive)).UnwrapOrThrow(); + activeRecords.Should().HaveCount(3); // All should be active now + + // Delete one record + await repository.RemoveById(record1.RecordId); + + var remainingRecords = (await repository.ListAll()).UnwrapOrThrow(); + remainingRecords.Should().HaveCount(2); + remainingRecords.Should().NotContain(r => r.RecordId == record1.RecordId); + } + + [Fact] + public async Task Remove_Should_Delete_Record() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("To Be Deleted", "Description", 999, true); + await repository.Add(testRecord); + + // Verify record exists before deletion + var beforeDeletion = await repository.GetById(testRecord.RecordId); + beforeDeletion.IsSome.Should().BeTrue(); + + // Act + await repository.Remove(testRecord); + + // Assert + var afterDeletion = await repository.GetById(testRecord.RecordId); + afterDeletion.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task RemoveById_Should_Delete_Record_By_Id() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("To Be Deleted By Id", "Description", 888, false); + await repository.Add(testRecord); + + // Verify record exists before deletion + var beforeDeletion = await repository.GetById(testRecord.RecordId); + beforeDeletion.IsSome.Should().BeTrue(); + + // Act + await repository.RemoveById(testRecord.RecordId); + + // Assert + var afterDeletion = await repository.GetById(testRecord.RecordId); + afterDeletion.IsNone.Should().BeTrue(); + } + + [Fact] + public async Task RemoveById_Should_Handle_Non_Existent_Id_Gracefully() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var nonExistentId = Guid.NewGuid(); + + // Act & Assert - Should not throw + var result = await repository.RemoveById(nonExistentId); + result.Should().Be(Unit.Default); + } + + [Fact] + public async Task Update_Should_Modify_Existing_Record() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var originalRecord = TestRecord.Create("Original Name", "Original Description", 100, false); + await repository.Add(originalRecord); + + // Act + var updatedRecord = originalRecord.Update(name: "Updated Name", value: 200, isActive: true); + await repository.Update(updatedRecord); + + // Assert + var retrieved = await repository.GetById(originalRecord.RecordId); + retrieved.IsSome.Should().BeTrue(); + + var record = retrieved.IfNone(() => throw new InvalidOperationException("Record should exist")); + record.Name.Should().Be("Updated Name"); + record.Description.Should().Be("Original Description"); // Should remain unchanged + record.Value.Should().Be(200); + record.IsActive.Should().BeTrue(); + record.UpdatedAt.Should().BeAfter(record.CreatedAt); + } + + [Fact] + public async Task Can_Store_And_Retrieve_Tags() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test", "Description", 1, true); + + // Act - Set tags + testRecord.SetTag("Category", "TestCategory", s => s); + testRecord.SetTag("Priority", "High", s => s); + + await repository.Add(testRecord); + + // Assert - Retrieve and verify tags + var retrieved = await repository.GetById(testRecord.RecordId); + _ = retrieved.Match( + record => + { + record.GetTag("Category", s => s).UnwrapOrThrow().Should().Be("TestCategory"); + record.GetTag("Priority", s => s).UnwrapOrThrow().Should().Be("High"); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Update_Tag() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test", "Description", 1, true); + + // Act - Set initial value then update + testRecord.SetTag("Status", "Initial", s => s); + testRecord.SetTag("Status", "Updated", s => s); + + await repository.Add(testRecord); + + // Assert - Should have updated value + var retrieved = await repository.GetById(testRecord.RecordId); + _ = retrieved.Match( + record => record.GetTag("Status", s => s).UnwrapOrThrow().Should().Be("Updated"), + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Not_Get_Non_Existent_Tag() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test", "Description", 1, true); + testRecord.SetTag("ExistingTag", "value", s => s); + + await repository.Add(testRecord); + + // Act & Assert - Should return null when accessing non-existent tag + var retrieved = await repository.GetById(testRecord.RecordId); + _ = retrieved.Match( + record => + { + var nonExistentTag = record.GetTag("NonExistentTag", s => s); + nonExistentTag.IsNone.Should().BeTrue(); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Remove_Tag() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test", "Description", 1, true); + + // Set a tag + testRecord.SetTag("TestTag", "testValue", s => s); + + await repository.Add(testRecord); + + // Act - Remove the tag + var retrieved = await repository.GetById(testRecord.RecordId); + var record = retrieved.IfNone(() => throw new InvalidOperationException("Record should exist")); + record.RemoveTag("TestTag"); + + await repository.Update(record); + + // Assert - Tag should be removed + var updatedRecord = await repository.GetById(testRecord.RecordId); + _ = updatedRecord.Match( + r => r.GetTag("TestTag", s => s).IsNone.Should().BeTrue(), + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Store_And_Retrieve_Complex_Object_With_Serialization() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test", "Description", 1, true); + + // Define serialization/deserialization functions + var serializeFunc = (DateTime dt) => dt.ToString("O"); // ISO 8601 format + var deserializeFunc = (string s) => DateTime.Parse(s); + + var testDate = new DateTime(2023, 12, 25, 10, 30, 0); + + // Act - Set complex object with serialization + testRecord.SetTag("LastUpdated", testDate, serializeFunc); + + await repository.Add(testRecord); + + // Assert - Retrieve and verify with deserialization + var retrieved = await repository.GetById(testRecord.RecordId); + _ = retrieved.Match( + record => + { + record.GetTag("LastUpdated", deserializeFunc).UnwrapOrThrow().Should().Be(testDate); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } + + [Fact] + public async Task Can_Store_And_Retrieve_Object_With_JSON_Serialization() + { + // Arrange + var databaseCreator = _serviceProvider.GetRequiredService(); + await databaseCreator.EnsureDatabaseCreated(); + + var repository = _serviceProvider.GetRequiredService>(); + var testRecord = TestRecord.Create("Test", "Description", 1, true); + + // Define JSON serialization/deserialization functions + var serializeFunc = (Dictionary dict) => JsonSerializer.Serialize(dict); + var deserializeFunc = (string json) => JsonSerializer.Deserialize>(json)!; + + var testData = new Dictionary + { + ["apples"] = 5, + ["bananas"] = 3, + ["oranges"] = 7 + }; + + // Act - Set complex object with JSON serialization + testRecord.SetTag("Inventory", testData, serializeFunc); + + await repository.Add(testRecord); + + // Assert - Retrieve and verify with JSON deserialization + var retrieved = await repository.GetById(testRecord.RecordId); + _ = retrieved.Match( + record => + { + var option = record.GetTag("Inventory", deserializeFunc); + _ = option.Match( + data => data.Should().BeEquivalentTo(testData), + () => throw new InvalidOperationException("Record should exist") + ); + }, + () => throw new InvalidOperationException("Record should exist") + ); + } +} diff --git a/test/WalletFramework.Storage.Tests/Usings.cs b/test/WalletFramework.Storage.Tests/Usings.cs new file mode 100644 index 00000000..8810c271 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/Usings.cs @@ -0,0 +1,2 @@ +global using SQLitePCL; + diff --git a/test/WalletFramework.Storage.Tests/WalletFramework.Storage.Tests.csproj b/test/WalletFramework.Storage.Tests/WalletFramework.Storage.Tests.csproj new file mode 100644 index 00000000..c2201af8 --- /dev/null +++ b/test/WalletFramework.Storage.Tests/WalletFramework.Storage.Tests.csproj @@ -0,0 +1,36 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + + +