├── ci
├── run-did-test-suite
│ ├── .gitignore
│ ├── app
│ │ ├── package.json
│ │ ├── testserver-utils.js
│ │ ├── local-files-utils.js
│ │ ├── utils.js
│ │ └── index.js
│ ├── action.yml
│ ├── entrypoint.sh
│ ├── Dockerfile
│ └── README.md
├── get-driver-status
│ ├── .gitignore
│ ├── app
│ │ ├── requirements.txt
│ │ └── get-driver-status.py
│ ├── Dockerfile
│ ├── action.yaml
│ ├── entrypoint.sh
│ └── README.md
├── docker-build-push
│ ├── Dockerfile
│ ├── README.md
│ └── entrypoint.sh
├── did-lint-check
│ └── run.sh
├── deploy-k8s-aws
│ ├── Dockerfile
│ ├── scripts
│ │ ├── process-env.sh
│ │ ├── parse-compose.sh
│ │ ├── handle-btcr-secret.sh
│ │ ├── deploy-frontend.sh
│ │ └── deploy-ingress.sh
│ └── action.yml
└── setup-aws-route53
│ ├── set-alias-dev.uniresolver.io.sh
│ ├── set-alias-resolver.identity.foundation.sh
│ └── setup-route53-guide.md
├── examples
├── sovrin
│ ├── lib
│ │ └── .gitignore
│ ├── localhost.txn
│ ├── danube.txn
│ └── mainnet.txn
├── .gitignore
├── src
│ └── main
│ │ ├── resources
│ │ └── log4j2.properties
│ │ └── java
│ │ └── uniresolver
│ │ └── examples
│ │ ├── TestDriverDidBtcr.java
│ │ ├── TestClientUniResolver.java
│ │ ├── TestDriverDidSov.java
│ │ ├── TestLocalUniResolver.java
│ │ ├── TestLocalUniDereferencer.java
│ │ └── w3ctestsuite
│ │ ├── TestIdentifier.java
│ │ ├── TestDIDResolution.java
│ │ ├── TestDIDURLDereferencing.java
│ │ └── TestSuiteUtil.java
└── pom.xml
├── uni-resolver-core
├── openapi
│ └── java-client-generated
│ │ ├── .openapi-generator-ignore
│ │ └── .gitignore
├── .gitignore
├── src
│ └── main
│ │ └── java
│ │ └── uniresolver
│ │ ├── w3c
│ │ ├── DIDResolver.java
│ │ └── DIDURLDereferencer.java
│ │ ├── UniDereferencer.java
│ │ ├── UniResolver.java
│ │ └── result
│ │ ├── ResolveResult.java
│ │ └── DereferenceResult.java
└── pom.xml
├── driver
├── .gitignore
├── src
│ └── main
│ │ └── java
│ │ └── uniresolver
│ │ └── driver
│ │ ├── AbstractDriver.java
│ │ ├── Driver.java
│ │ ├── util
│ │ └── MediaTypeUtil.java
│ │ └── servlet
│ │ ├── InitServlet.java
│ │ ├── PropertiesServlet.java
│ │ └── ServletUtil.java
└── pom.xml
├── docs
├── logo-dif.png
├── logo-ngi0pet.png
├── figures
│ ├── overview.png
│ ├── protocol.png
│ ├── architecture.png
│ └── aws-architecture.png
├── troubleshooting.md
├── design-goals.md
├── java-components.md
├── continuous-integration-and-delivery.md
├── dev-system.md
└── branching-strategy.md
├── driver-http
├── .gitignore
└── pom.xml
├── uni-resolver-client
├── .gitignore
└── pom.xml
├── uni-resolver-local
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── uniresolver
│ └── local
│ ├── extensions
│ ├── impl
│ │ ├── DummyResolverExtension.java
│ │ ├── DummyDereferencerExtension.java
│ │ └── DIDDocumentExtension.java
│ ├── ResolverExtension.java
│ ├── DereferencerExtension.java
│ ├── ExtensionStatus.java
│ └── util
│ │ └── ExecutionStateUtil.java
│ └── configuration
│ └── LocalUniResolverConfigurator.java
├── uni-resolver-web
├── .gitignore
├── src
│ ├── test
│ │ └── resources
│ │ │ ├── jetty.xml
│ │ │ ├── jetty-env.xml
│ │ │ └── log4j2-test.xml
│ └── main
│ │ ├── resources
│ │ ├── application-dev.yml
│ │ └── log4j2.xml
│ │ └── java
│ │ └── uniresolver
│ │ └── web
│ │ ├── config
│ │ ├── ServletMappings.java
│ │ └── DriverConfigs.java
│ │ ├── WebUniResolverApplication.java
│ │ ├── WebUniResolverWebServerFactoryCustomizer.java
│ │ ├── servlet
│ │ ├── MethodsServlet.java
│ │ ├── TraitsServlet.java
│ │ ├── PropertiesServlet.java
│ │ ├── TestIdentifiersServlet.java
│ │ └── ServletUtil.java
│ │ └── WebUniResolver.java
├── docker
│ └── Dockerfile
└── pom.xml
├── .gitignore
├── .github
├── dependabot.yml
└── workflows
│ ├── nightly-did-lint-check.yml
│ ├── nightly-did-test-suite.yml
│ ├── kubernetes-deploy-to-cluster.yml
│ ├── archive_lint_reports.yml
│ ├── release.yml
│ ├── latest.yml
│ └── docker-multi-arch.yml
├── .gitlab-ci.yml
└── .env
/ci/run-did-test-suite/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules
--------------------------------------------------------------------------------
/examples/sovrin/lib/.gitignore:
--------------------------------------------------------------------------------
1 | libindy.so
2 |
3 | /.idea/
4 | *.iml
5 |
--------------------------------------------------------------------------------
/uni-resolver-core/openapi/java-client-generated/.openapi-generator-ignore:
--------------------------------------------------------------------------------
1 | .gitignore
--------------------------------------------------------------------------------
/ci/get-driver-status/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /app/config.json
3 | /app/driver-status-result-*.json
4 |
--------------------------------------------------------------------------------
/driver/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target
5 | /bin/
6 | /.idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target
5 | /bin/
6 | /.idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/uni-resolver-core/openapi/java-client-generated/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 | !.openapi-generator-ignore
--------------------------------------------------------------------------------
/docs/logo-dif.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/decentralized-identity/universal-resolver/HEAD/docs/logo-dif.png
--------------------------------------------------------------------------------
/driver-http/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target
5 | /bin/
6 | /.idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/uni-resolver-client/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target
5 | /bin/
6 | /.idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/uni-resolver-core/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target
5 | /bin/
6 | /.idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/uni-resolver-local/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target
5 | /bin/
6 | /.idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/uni-resolver-web/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target
5 | /bin/
6 | /.idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/ci/get-driver-status/app/requirements.txt:
--------------------------------------------------------------------------------
1 | aiofiles==0.6.0
2 | aiohttp==3.8.5
3 | async-timeout==3.0.1
4 | pyyaml==5.4
5 |
--------------------------------------------------------------------------------
/docs/logo-ngi0pet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/decentralized-identity/universal-resolver/HEAD/docs/logo-ngi0pet.png
--------------------------------------------------------------------------------
/docs/figures/overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/decentralized-identity/universal-resolver/HEAD/docs/figures/overview.png
--------------------------------------------------------------------------------
/docs/figures/protocol.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/decentralized-identity/universal-resolver/HEAD/docs/figures/protocol.png
--------------------------------------------------------------------------------
/docs/figures/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/decentralized-identity/universal-resolver/HEAD/docs/figures/architecture.png
--------------------------------------------------------------------------------
/docs/figures/aws-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/decentralized-identity/universal-resolver/HEAD/docs/figures/aws-architecture.png
--------------------------------------------------------------------------------
/driver/src/main/java/uniresolver/driver/AbstractDriver.java:
--------------------------------------------------------------------------------
1 | package uniresolver.driver;
2 |
3 | public abstract class AbstractDriver implements Driver {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /.settings/
4 | /target/
5 | /bin/
6 | docker-compose.override.yml
7 | /.idea/
8 | *.iml
9 | .vscode/
10 | .factorypath
11 | Makefile
12 | **/deploy/
--------------------------------------------------------------------------------
/uni-resolver-web/src/test/resources/jetty.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/test/resources/jetty-env.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/uni-resolver-core/src/main/java/uniresolver/w3c/DIDResolver.java:
--------------------------------------------------------------------------------
1 | package uniresolver.w3c;
2 |
3 | import uniresolver.ResolutionException;
4 | import uniresolver.result.ResolveResult;
5 |
6 | import java.util.Map;
7 |
8 | public interface DIDResolver {
9 |
10 | public ResolveResult resolve(String didString, Map resolutionOptions) throws ResolutionException;
11 | }
12 |
--------------------------------------------------------------------------------
/uni-resolver-core/src/main/java/uniresolver/w3c/DIDURLDereferencer.java:
--------------------------------------------------------------------------------
1 | package uniresolver.w3c;
2 |
3 | import uniresolver.DereferencingException;
4 | import uniresolver.ResolutionException;
5 | import uniresolver.result.DereferenceResult;
6 |
7 | import java.util.Map;
8 |
9 | public interface DIDURLDereferencer {
10 |
11 | public DereferenceResult dereference(String didUrlString, Map dereferenceOptions) throws DereferencingException, ResolutionException;
12 | }
13 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 | management:
2 | endpoints:
3 | web:
4 | exposure:
5 | include: '*'
6 | health:
7 | readinessState:
8 | enabled: 'true'
9 | livenessState:
10 | enabled: 'true'
11 | endpoint:
12 | health:
13 | probes:
14 | enabled: 'true'
15 | show-details: always
16 | status:
17 | http-mapping:
18 | down: '500'
19 | warning: '500'
20 | out_of_service: '503'
21 |
--------------------------------------------------------------------------------
/ci/run-did-test-suite/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "run-did-test-suite",
3 | "version": "1.0.0",
4 | "description": "Run did-test-suite action",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Bernhard Fuchs",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@actions/core": "^1.2.7",
13 | "@actions/github": "^4.0.0",
14 | "axios": "^0.21.2",
15 | "dayjs": "^1.10.4",
16 | "minimist": "^1.2.6"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | # Maintain dependencies for GitHub Actions
9 | - package-ecosystem: github-actions
10 | directory: /
11 | schedule:
12 | interval: weekly
13 |
--------------------------------------------------------------------------------
/ci/docker-build-push/Dockerfile:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | FROM docker:stable
3 |
4 | LABEL "name"="Docker build/push Action"
5 | LABEL "maintainer"="Phil "
6 | LABEL "version"="1.0.0"
7 |
8 | LABEL "com.github.actions.name"="Docker build/push Action"
9 | LABEL "com.github.actions.description"="GitHub Action for building and pushing a Docker container"
10 | LABEL "com.github.actions.icon"="package"
11 | LABEL "com.github.actions.color"="blue"
12 |
13 | ADD entrypoint.sh /entrypoint.sh
14 | RUN chmod +x /entrypoint.sh
15 | ENTRYPOINT ["/entrypoint.sh"]
16 |
--------------------------------------------------------------------------------
/ci/run-did-test-suite/action.yml:
--------------------------------------------------------------------------------
1 | name: 'uni-resolver-did-test-suite'
2 | description: 'Run did-test-suite against Universal Resolver deployment'
3 | inputs:
4 | host:
5 | description: 'Host of Uni-Resolver deployment'
6 | required: false
7 | driver_status_report:
8 | description: 'File with testset of Uni-resolver response'
9 | required: false
10 | reports_folder:
11 | description: 'Destination folder of reports'
12 | required: true
13 | runs:
14 | using: 'docker'
15 | image: 'Dockerfile'
16 | args:
17 | - ${{ inputs.host }}
18 | - ${{ inputs.driver_status_report }}
19 | - ${{ inputs.reports_folder }}
--------------------------------------------------------------------------------
/docs/troubleshooting.md:
--------------------------------------------------------------------------------
1 | # Universal Resolver — Troubleshooting
2 |
3 | If docker-compose complains about wrong versions then you probably have a too old docker-compose version.
4 |
5 | On Ubuntu 16.04 remove docker-compose and install a new version e.g.
6 | ```
7 | sudo apt-get remove docker-compose
8 | curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
9 | chmod +x /usr/local/bin/docker-compose
10 | ```
11 | You might want to adjust the version number 1.22.0 to the latest one. Please see: [Installing docker-compose](https://docs.docker.com/compose/install/#install-compose)
12 |
13 |
--------------------------------------------------------------------------------
/ci/run-did-test-suite/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | echo "#### Run did-test-suite ####"
4 |
5 | echo "Running with parameters:"
6 | sh -c "echo $*"
7 |
8 | echo "host: $INPUT_HOST"
9 | echo "driver_status_report: $INPUT_DRIVER_STATUS_REPORT"
10 |
11 | node /run-did-test-suite/index.js --HOST="$INPUT_HOST" --DRIVER_STATUS_REPORT="$INPUT_DRIVER_STATUS_REPORT" --OUTPUT_PATH="$INPUT_REPORTS_FOLDER"
12 |
13 | echo "Push report file to repo"
14 | git status
15 | git config --global user.email "admin@danubetech.com"
16 | git config --global user.name "Get driver status workflow"
17 | git fetch && git pull --ff-only
18 | git add . && git commit -m "did-test-suite report" && git push
--------------------------------------------------------------------------------
/.github/workflows/nightly-did-lint-check.yml:
--------------------------------------------------------------------------------
1 | name: Nightly DID Lint check
2 |
3 | on:
4 | schedule:
5 | - cron: '0 6,12,18,0 * * *'
6 | workflow_dispatch:
7 |
8 | jobs:
9 | did-lint-check:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@master
13 | - name: Did Lint check
14 | run: ./ci/did-lint-check/run.sh
15 |
16 | - name: Slack notification
17 | uses: 8398a7/action-slack@v3
18 | with:
19 | status: ${{ job.status }}
20 | fields: repo,commit,action,eventName,ref,workflow
21 | env:
22 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
23 | if: failure()
24 |
--------------------------------------------------------------------------------
/uni-resolver-core/src/main/java/uniresolver/UniDereferencer.java:
--------------------------------------------------------------------------------
1 | package uniresolver;
2 |
3 | import uniresolver.result.DereferenceResult;
4 | import uniresolver.w3c.DIDURLDereferencer;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | public interface UniDereferencer extends DIDURLDereferencer {
10 |
11 | @Override public DereferenceResult dereference(String didUrlString, Map dereferenceOptions) throws DereferencingException, ResolutionException;
12 |
13 | default public DereferenceResult dereference(String didUrlString) throws DereferencingException, ResolutionException {
14 | return this.dereference(didUrlString, new HashMap<>());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ci/run-did-test-suite/app/testserver-utils.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios');
2 | const fs = require('fs');
3 |
4 | const runTests = (resolvers, host, outputPath) => {
5 | axios.post(host,
6 | {
7 | suites: [
8 | {
9 | suite_name: 'did-resolution',
10 | resolvers: resolvers
11 | }
12 | ]
13 | }
14 | ).then(res => {
15 | const timestamp = new Date().toISOString().split('.')[0];
16 | fs.writeFileSync(`${outputPath}/did-test-suite-report-${timestamp}.json`, JSON.stringify(res.data.suitesReportJson, null, 2))
17 | }).catch(err => console.log(err));
18 | }
19 |
20 | module.exports = {runTests}
21 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/test/resources/log4j2-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | image: docker:latest
2 |
3 | services:
4 | - docker:dind
5 |
6 | before_script:
7 | - echo -n $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
8 |
9 | build-master:
10 | stage: build
11 | script:
12 | - cd resolver/java/uni-resolver-web/
13 | - docker build -f ./docker/Dockerfile --pull -t "$CI_REGISTRY_IMAGE" .
14 | - docker push "$CI_REGISTRY_IMAGE"
15 | only:
16 | - master
17 |
18 | build:
19 | stage: build
20 | script:
21 | - cd resolver/java/uni-resolver-web/
22 | - docker build -f ./docker/Dockerfile --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" .
23 | - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
24 | except:
25 | - master
26 |
--------------------------------------------------------------------------------
/examples/src/main/resources/log4j2.properties:
--------------------------------------------------------------------------------
1 | status=error
2 | dest=err
3 | name=testLoggerConfig
4 |
5 | filter.threshold.type=ThresholdFilter
6 | filter.threshold.level=debug
7 |
8 | appender.console.type=Console
9 | appender.console.name=STDOUT
10 | appender.console.layout.type=PatternLayout
11 | appender.console.layout.pattern=%highlight{[%t] %p %c{2} (%M) -} %highlight{%m%n%throwable}{STYLE=Logback}
12 | appender.console.filter.threshold.type=ThresholdFilter
13 | appender.console.filter.threshold.level=debug
14 |
15 | logger.uniresolver.name=uniresolver
16 | logger.uniresolver.level=debug
17 |
18 | logger.timeoutHandler.name=org.bitcoinj.core.PeerSocketHandler
19 | logger.timeoutHandler.level=error
20 |
21 | rootLogger.level=info
22 | rootLogger.additivity=false
23 | rootLogger.appenderRefs=stdout
24 | rootLogger.appenderRef.stdout.ref=STDOUT
25 |
--------------------------------------------------------------------------------
/ci/get-driver-status/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10-buster
2 |
3 | LABEL "com.github.actions.name"="Get driver status"
4 | LABEL "com.github.actions.description"="Get driver status for a Universal Resolver deployment"
5 | LABEL "com.github.actions.icon"="mic"
6 | LABEL "com.github.actions.color"="blue"
7 | LABEL "version"="1.0.0"
8 | LABEL "repository"="https://github.com/decentralized-identity/universal-resolver"
9 | LABEL "homepage"="https://uniresolver.io"
10 | LABEL "maintainer"="Bernhard Fuchs "
11 |
12 | RUN apt-get update && \
13 | apt-get upgrade -y
14 |
15 | WORKDIR /get-driver-status/
16 |
17 | COPY app/requirements.txt .
18 | RUN pip install --no-cache-dir -r requirements.txt
19 |
20 | COPY app/get-driver-status.py .
21 |
22 | COPY entrypoint.sh /
23 | RUN chmod +x /entrypoint.sh
24 | ENTRYPOINT ["/entrypoint.sh"]
25 |
--------------------------------------------------------------------------------
/driver-http/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | uni-resolver-driver-http
5 | jar
6 | uni-resolver-driver-http
7 |
8 |
9 | decentralized-identity
10 | uni-resolver
11 | 0.48-SNAPSHOT
12 |
13 |
14 |
15 |
16 | decentralized-identity
17 | uni-resolver-driver
18 |
19 |
20 | org.apache.httpcomponents
21 | httpclient
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ci/did-lint-check/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "Pulling did-status-generator image"
4 | docker pull oydeu/did-status-generator:latest
5 |
6 | echo "Running did-status-generator image"
7 | docker run --rm -e "DID_RESOLVER=https://resolver.identity.foundation/1.0/identifiers/" oydeu/did-status-generator:latest > result.json
8 | echo "Set result.json to result_var"
9 | result_var=$(cat result.json)
10 |
11 | echo "Checkout to did-lint-reports branch"
12 | git fetch
13 | git switch did-lint-reports --force
14 |
15 | echo "Replace old result.json with result_var"
16 | echo "$result_var" > result.json
17 |
18 | echo "Push result file to repo"
19 | git config --global user.email "admin@danubetech.com"
20 | git config --global user.name "DID Lint check workflow"
21 | git status
22 | git add result.json
23 | git commit -m "DID Lint check reports"
24 | git push origin did-lint-reports:did-lint-reports
25 |
--------------------------------------------------------------------------------
/ci/run-did-test-suite/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:lts-alpine3.13
2 |
3 | LABEL "com.github.actions.name"="Did Test Suite"
4 | LABEL "com.github.actions.description"="Run the did-test-suite against the api of a Universal Resolver deployment"
5 | LABEL "com.github.actions.icon"="mic"
6 | LABEL "com.github.actions.color"="blue"
7 | LABEL "version"="1.0.0"
8 | LABEL "repository"="https://github.com/decentralized-identity/universal-resolver"
9 | LABEL "homepage"="https://uniresolver.io"
10 | LABEL "maintainer"="Bernhard Fuchs "
11 |
12 | RUN apk update && apk upgrade && \
13 | apk add --no-cache git
14 |
15 | WORKDIR /run-did-test-suite/
16 |
17 | COPY app/package.json .
18 | RUN npm install
19 |
20 | COPY app/index.js .
21 | COPY app/local-files-utils.js .
22 | COPY app/testserver-utils.js .
23 | COPY app/utils.js .
24 |
25 | COPY entrypoint.sh /
26 | RUN chmod +x /entrypoint.sh
27 | ENTRYPOINT ["/entrypoint.sh"]
--------------------------------------------------------------------------------
/examples/src/main/java/uniresolver/examples/TestDriverDidBtcr.java:
--------------------------------------------------------------------------------
1 | package uniresolver.examples;
2 | import foundation.identity.did.DID;
3 | import info.weboftrust.btctxlookup.bitcoinconnection.BlockcypherAPIBitcoinConnection;
4 | import uniresolver.driver.did.btcr2.DidBtcrDriver;
5 | import uniresolver.result.ResolveDataModelResult;
6 | import uniresolver.result.ResolveResult;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class TestDriverDidBtcr {
12 |
13 | public static void main(String[] args) throws Exception {
14 |
15 | Map driverProperties = new HashMap<>();
16 | driverProperties.put("bitcoinConnection", "blockcypherapi");
17 | DidBtcrDriver driver = new DidBtcrDriver(driverProperties);
18 |
19 | Map resolveOptions = new HashMap<>();
20 | ResolveResult resolveResult = driver.resolve(DID.fromString("did:btcr:x705-jznz-q3nl-srs"), resolveOptions);
21 | System.out.println(resolveResult.toJson());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ci/get-driver-status/action.yaml:
--------------------------------------------------------------------------------
1 | name: 'uni-resolver-get-driver-status'
2 | description: 'Get driver status for Universal Resolver deployment'
3 | inputs:
4 | host:
5 | description: 'Host of Uni-Resolver deployment'
6 | required: false
7 | default: https://dev.uniresolver.io
8 | config:
9 | description: 'Uni-Resolver configuration file'
10 | required: false
11 | default: /github/workspace/uni-resolver-web/src/main/resources/application.yml
12 | out:
13 | description: 'Folder location of driver-status-result- file'
14 | required: false
15 | default: /github/workspace/uni-resolver-web/driver-status-reports
16 | debug:
17 | description: 'Enhance logging'
18 | required: false
19 | default: false
20 | keep_result:
21 | description: 'Keep result file'
22 | required: false
23 | default: false
24 | runs:
25 | using: 'docker'
26 | image: 'Dockerfile'
27 | args:
28 | - ${{ inputs.host }}
29 | - ${{ inputs.config }}
30 | - ${{ inputs.out_folder }}
31 |
--------------------------------------------------------------------------------
/uni-resolver-local/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | uni-resolver-local
5 | jar
6 | uni-resolver-local
7 |
8 |
9 | decentralized-identity
10 | uni-resolver
11 | 0.48-SNAPSHOT
12 |
13 |
14 |
15 |
16 | decentralized-identity
17 | uni-resolver-core
18 |
19 |
20 | decentralized-identity
21 | uni-resolver-driver
22 |
23 |
24 | decentralized-identity
25 | uni-resolver-driver-http
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/examples/src/main/java/uniresolver/examples/TestClientUniResolver.java:
--------------------------------------------------------------------------------
1 | package uniresolver.examples;
2 |
3 | import uniresolver.client.ClientUniResolver;
4 | import uniresolver.result.ResolveDataModelResult;
5 | import uniresolver.result.ResolveRepresentationResult;
6 | import uniresolver.result.ResolveResult;
7 |
8 | import java.nio.charset.StandardCharsets;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | public class TestClientUniResolver {
13 |
14 | public static void main(String[] args) throws Exception {
15 |
16 | Map resolveOptions = new HashMap<>();
17 | resolveOptions.put("accept", "application/did");
18 |
19 | ClientUniResolver uniResolver = new ClientUniResolver();
20 | uniResolver.setResolveUri("http://localhost:8080/1.0/identifiers/");
21 |
22 | ResolveRepresentationResult resolveRepresentationResult = uniResolver.resolveRepresentation("did:sov:WRfXPg8dantKVubE3HX8pw", resolveOptions);
23 | System.out.println(resolveRepresentationResult.toJson());
24 | System.out.println(new String(resolveRepresentationResult.getDidDocumentStream(), StandardCharsets.UTF_8));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.github/workflows/nightly-did-test-suite.yml:
--------------------------------------------------------------------------------
1 | name: Nightly did-test-suite
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | driver-health-check:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@master
11 | - name: Get driver status
12 | uses: ./ci/get-driver-status
13 | with:
14 | host: https://dev.uniresolver.io
15 | out: /home/runner/work/universal-resolver/universal-resolver/driver-status-reports
16 | keep_result: true
17 | # - name: Run did-test-suite
18 | # uses: ./ci/run-did-test-suite
19 | # with:
20 | # host: https://did-test-suite.uniresolver.io/test-suite-manager/generate-report
21 | # driver_status_report: ${{ env.driver_status_report }}
22 | # reports_folder: ${{ env.reports_folder }}
23 | - name: Slack notification
24 | uses: 8398a7/action-slack@v3
25 | with:
26 | status: ${{ job.status }}
27 | fields: repo,commit,action,eventName,ref,workflow
28 | env:
29 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
30 | if: failure()
31 |
--------------------------------------------------------------------------------
/examples/src/main/java/uniresolver/examples/TestDriverDidSov.java:
--------------------------------------------------------------------------------
1 | package uniresolver.examples;
2 |
3 | import foundation.identity.did.DID;
4 | import uniresolver.driver.did.sov.DidSovDriver;
5 | import uniresolver.result.ResolveDataModelResult;
6 | import uniresolver.result.ResolveResult;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class TestDriverDidSov {
12 |
13 | public static void main(String[] args) throws Exception {
14 |
15 | DidSovDriver driver = new DidSovDriver();
16 | driver.setLibIndyPath("./sovrin/lib/libindy.so");
17 | driver.setPoolConfigs("_;./sovrin/mainnet.txn");
18 | driver.setPoolVersions("_;2");
19 |
20 | Map resolveOptions = new HashMap<>();
21 | resolveOptions.put("accept", "application/did");
22 |
23 | ResolveResult resolveResult;
24 | resolveResult = driver.resolve(DID.fromString("did:sov:WRfXPg8dantKVubE3HX8pw"), resolveOptions);
25 | System.out.println(resolveResult.toJson());
26 | resolveResult = driver.resolveRepresentation(DID.fromString("did:sov:WRfXPg8dantKVubE3HX8pw"), resolveOptions);
27 | System.out.println(resolveResult.toJson());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/uni-resolver-web/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | # Dockerfile for universalresolver/uni-resolver-web
2 |
3 | FROM maven:3-eclipse-temurin-21 AS build
4 | MAINTAINER Markus Sabadello
5 |
6 | # build uni-resolver-web
7 |
8 | ADD . /opt/universal-resolver
9 | RUN cd /opt/universal-resolver && mvn clean install -N
10 | RUN cd /opt/universal-resolver/uni-resolver-core && mvn clean install -N
11 | RUN cd /opt/universal-resolver/driver && mvn clean install -N
12 | RUN cd /opt/universal-resolver/driver-http && mvn clean install -N
13 | RUN cd /opt/universal-resolver/uni-resolver-local && mvn clean install -N
14 | RUN cd /opt/universal-resolver/uni-resolver-web && mvn clean package -N
15 |
16 | # build image
17 |
18 | FROM eclipse-temurin:21-jre-alpine
19 | # For amd64 architecture use amd64/eclipse-temurin:17-jre-alpine
20 |
21 | MAINTAINER Markus Sabadello
22 |
23 | WORKDIR /opt/universal-resolver/uni-resolver-web/
24 |
25 | COPY --from=build /opt/universal-resolver/uni-resolver-web/target/*-exec.jar ./
26 |
27 | ENV uniresolver_web_spring_profiles_active=default
28 |
29 | # done
30 |
31 | EXPOSE 8080
32 | CMD java -jar *.jar
33 |
--------------------------------------------------------------------------------
/uni-resolver-local/src/main/java/uniresolver/local/extensions/impl/DummyResolverExtension.java:
--------------------------------------------------------------------------------
1 | package uniresolver.local.extensions.impl;
2 |
3 | import foundation.identity.did.DID;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import uniresolver.ResolutionException;
7 | import uniresolver.local.LocalUniResolver;
8 | import uniresolver.local.extensions.ExtensionStatus;
9 | import uniresolver.local.extensions.ResolverExtension;
10 | import uniresolver.local.extensions.ResolverExtension.AbstractResolverExtension;
11 | import uniresolver.result.ResolveResult;
12 |
13 | import java.util.Map;
14 |
15 | public class DummyResolverExtension extends AbstractResolverExtension implements ResolverExtension {
16 |
17 | private static final Logger log = LoggerFactory.getLogger(DummyResolverExtension.class);
18 |
19 | @Override
20 | public ExtensionStatus afterResolve(DID did, Map resolutionOptions, ResolveResult resolveResult, Map executionState, LocalUniResolver localUniResolver) throws ResolutionException {
21 |
22 | if (log.isDebugEnabled()) log.debug("Dummy extension called!");
23 | return ExtensionStatus.DEFAULT;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/docs/design-goals.md:
--------------------------------------------------------------------------------
1 | # Universal Resolver — Design Goals
2 |
3 | The main design objectives of the UR are:
4 |
5 | * **Generic:** The UR will be a neutral implementation that will be usable as broadly as possible, i.e. not limited towards a specific use case or higher-level protocol.
6 | * **Simple:** The most common uses of the UR should be very simple to execute (e.g. "give me the DDO or the Hub endpoint for this identifier").
7 | * **Extensible:** The UR may ship by default with a few key implementations of common identifier systems, but must also be extensible to easily add new ones through a plugin mechanism.
8 |
9 | The following functionality is out of scope for the UR:
10 |
11 | * The UR will not address registration or modification of identifiers and associated data.
12 | * The UR will not involve authentication or authorization of the UR user, i.e. all its functionality will be publicly usable by anyone. [debatable?]
13 | * The UR will not implement any functionality that builds on top of resolution, such as the DIF Hub protocols, Blockstack storage layer, XDI, DID Auth, DKMS, etc. [debatable?], but it will be able to serve as a building block for such higher-level protocols.
14 |
--------------------------------------------------------------------------------
/examples/src/main/java/uniresolver/examples/TestLocalUniResolver.java:
--------------------------------------------------------------------------------
1 | package uniresolver.examples;
2 |
3 | import uniresolver.driver.did.sov.DidSovDriver;
4 | import uniresolver.local.LocalUniResolver;
5 | import uniresolver.result.ResolveResult;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public class TestLocalUniResolver {
11 |
12 | public static void main(String[] args) throws Exception {
13 |
14 | LocalUniResolver uniResolver = new LocalUniResolver();
15 | uniResolver.getDrivers().add(new DidSovDriver());
16 | uniResolver.getDriver(DidSovDriver.class).setLibIndyPath("./sovrin/lib/libindy.so");
17 | uniResolver.getDriver(DidSovDriver.class).setPoolConfigs("_;./sovrin/mainnet.txn");
18 | uniResolver.getDriver(DidSovDriver.class).setPoolVersions("_;2");
19 |
20 | Map resolveOptions = new HashMap<>();
21 | resolveOptions.put("accept", "application/did");
22 |
23 | ResolveResult resolveResult;
24 | resolveResult = uniResolver.resolve("did:sov:WRfXPg8dantKVubE3HX8pw", resolveOptions);
25 | System.out.println(resolveResult.toJson());
26 | resolveResult = uniResolver.resolveRepresentation("did:sov:WRfXPg8dantKVubE3HX8pw", resolveOptions);
27 | System.out.println(resolveResult.toJson());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ci/run-did-test-suite/app/local-files-utils.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs")
2 |
3 | const generateLocalFile = (testData, methodName, path) => {
4 | fs.writeFileSync(
5 | `${path}/universal-resolver-did-${methodName}.json`,
6 | JSON.stringify(testData, null, 4)
7 | );
8 | };
9 |
10 | const generateDefaultFile = (path) => {
11 | fs.readdir(path, (err, files) => {
12 |
13 | const resolvers = []
14 |
15 | files.forEach(file => {
16 | console.log(file);
17 | const fileContent = JSON.parse(fs.readFileSync(`${path}/${file}`));
18 | console.log(fileContent);
19 | if (file.startsWith('universal-resolver') || file.startsWith('resolver')) {
20 | resolvers.push(`require('../implementations/${file}')`)
21 | }
22 | });
23 | console.log(resolvers)
24 |
25 | fs.writeFileSync(
26 | '/Users/devfox/testsuites/did-test-suite/packages/did-core-test-server/suites/did-resolution/default.js',
27 | `module.exports = {
28 | name: '7.1 DID Resolution',
29 | resolvers: [${resolvers}]
30 | }`
31 | );
32 | });
33 | };
34 |
35 | module.exports = {
36 | generateDefaultFile,
37 | generateLocalFile
38 | }
39 |
--------------------------------------------------------------------------------
/examples/src/main/java/uniresolver/examples/TestLocalUniDereferencer.java:
--------------------------------------------------------------------------------
1 | package uniresolver.examples;
2 |
3 | import uniresolver.driver.did.sov.DidSovDriver;
4 | import uniresolver.local.LocalUniDereferencer;
5 | import uniresolver.local.LocalUniResolver;
6 | import uniresolver.result.DereferenceResult;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class TestLocalUniDereferencer {
12 |
13 | public static void main(String[] args) throws Exception {
14 |
15 | LocalUniResolver uniResolver = new LocalUniResolver();
16 | uniResolver.getDrivers().add(new DidSovDriver());
17 | uniResolver.getDriver(DidSovDriver.class).setLibIndyPath("./sovrin/lib/libindy.so");
18 | uniResolver.getDriver(DidSovDriver.class).setPoolConfigs("_;./sovrin/mainnet.txn");
19 | uniResolver.getDriver(DidSovDriver.class).setPoolVersions("_;2");
20 |
21 | LocalUniDereferencer uniDereferencer = new LocalUniDereferencer();
22 | uniDereferencer.setUniResolver(uniResolver);
23 |
24 | Map dereferenceOptions = new HashMap<>();
25 | dereferenceOptions.put("accept", "application/did");
26 | DereferenceResult dereferenceResult = uniDereferencer.dereference("did:sov:WRfXPg8dantKVubE3HX8pw#key-1", dereferenceOptions);
27 | System.out.println(dereferenceResult.toJson());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/uni-resolver-local/src/main/java/uniresolver/local/extensions/impl/DummyDereferencerExtension.java:
--------------------------------------------------------------------------------
1 | package uniresolver.local.extensions.impl;
2 |
3 | import foundation.identity.did.DIDURL;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import uniresolver.DereferencingException;
7 | import uniresolver.ResolutionException;
8 | import uniresolver.local.LocalUniDereferencer;
9 | import uniresolver.local.extensions.DereferencerExtension;
10 | import uniresolver.local.extensions.DereferencerExtension.AbstractDereferencerExtension;
11 | import uniresolver.local.extensions.ExtensionStatus;
12 | import uniresolver.result.DereferenceResult;
13 |
14 | import java.util.Map;
15 |
16 | public class DummyDereferencerExtension extends AbstractDereferencerExtension implements DereferencerExtension {
17 |
18 | private static final Logger log = LoggerFactory.getLogger(DummyDereferencerExtension.class);
19 |
20 | @Override
21 | public ExtensionStatus afterDereference(DIDURL didUrl, Map dereferenceOptions, DereferenceResult dereferenceResult, Map executionState, LocalUniDereferencer localUniDereferencer) throws ResolutionException, DereferencingException {
22 |
23 | if (log.isDebugEnabled()) log.debug("Dummy extension called!");
24 | return ExtensionStatus.DEFAULT;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/sovrin/localhost.txn:
--------------------------------------------------------------------------------
1 | {"data":{"alias":"Node1","client_ip":"10.0.0.2","client_port":9702,"node_ip":"10.0.0.2","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv","identifier":"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4","txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62","type":"0"}
2 | {"data":{"alias":"Node2","client_ip":"10.0.0.2","client_port":9704,"node_ip":"10.0.0.2","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb","identifier":"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy","txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc","type":"0"}
3 | {"data":{"alias":"Node3","client_ip":"10.0.0.2","client_port":9706,"node_ip":"10.0.0.2","node_port":9705,"services":["VALIDATOR"]},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya","identifier":"2yAeV5ftuasWNgQwVYzeHeTuM7LwwNtPR3Zg9N4JiDgF","txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4","type":"0"}
4 | {"data":{"alias":"Node4","client_ip":"10.0.0.2","client_port":9708,"node_ip":"10.0.0.2","node_port":9707,"services":["VALIDATOR"]},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA","identifier":"FTE95CVthRtrBnK2PYCBbC9LghTcGwi9Zfi1Gz2dnyNx","txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008","type":"0"}
5 |
--------------------------------------------------------------------------------
/ci/docker-build-push/README.md:
--------------------------------------------------------------------------------
1 | # Github Action
2 |
3 | GitHub Action for building and publishing a Docker container to Docker Hub.
4 |
5 |
6 | ## Secrets
7 |
8 | - `DOCKER_USERNAME` - *Required* Name of Docker Hub user which has **Write access**
9 | - `DOCKER_PASSWORD` - *Required* Password of the Docker Hub user
10 |
11 | Setup secrets in your GitHub project at "Settings > Secrets"
12 |
13 | ## Environment Variables
14 |
15 |
16 | - `CONTAINER_TAG` : **mandatory**, example: 'universalresolver/driver-did-btcr:latest'
17 | - `DOCKER_FILE` : **optional**, default is **Dockerfile**
18 |
19 |
20 | ## Example
21 |
22 |
23 | ```yaml
24 | name: CI/CD Workflow for driver-did-btcr
25 |
26 | on:
27 | push:
28 | branches:
29 | - master
30 | pull_request:
31 | branches:
32 | - master
33 |
34 | jobs:
35 | build:
36 | runs-on: ubuntu-latest
37 | steps:
38 | - uses: actions/checkout@master
39 | - name: Docker Build and Push
40 | uses: .ci/docker-build-push
41 | env:
42 | DOCKER_USERNAME: ${{secrets.DOCKER_USERNAME}}
43 | DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
44 | DOCKER_FILE: docker/Dockerfile
45 | CONTAINER_TAG: universalresolver/driver-did-btcr:latest
46 | ```
47 |
48 | ## LICENSE
49 |
50 | Copyright (c) 2020
51 |
52 | Licensed under the Apache2 License.
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/java/uniresolver/web/config/ServletMappings.java:
--------------------------------------------------------------------------------
1 | package uniresolver.web.config;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | @Configuration
7 | @ConfigurationProperties("server.servlet.mappings")
8 | public class ServletMappings {
9 |
10 | private String properties;
11 | private String resolve;
12 | private String methods;
13 | private String testIdentifiers;
14 | private String traits;
15 |
16 | public String getProperties() {
17 | return properties;
18 | }
19 |
20 | public String getResolve() {
21 | return resolve;
22 | }
23 |
24 | public String getMethods() {
25 | return methods;
26 | }
27 |
28 | public String getTestIdentifiers() {
29 | return testIdentifiers;
30 | }
31 |
32 | public String getTraits() {
33 | return traits;
34 | }
35 |
36 | public void setProperties(String properties) {
37 | this.properties = properties;
38 | }
39 |
40 | public void setResolve(String resolve) {
41 | this.resolve = resolve;
42 | }
43 |
44 | public void setMethods(String methods) {
45 | this.methods = methods;
46 | }
47 |
48 | public void setTestIdentifiers(String testIdentifiers) {
49 | this.testIdentifiers = testIdentifiers;
50 | }
51 |
52 | public void setTraits(String traits) {
53 | this.traits = traits;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/uni-resolver-client/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | uni-resolver-client
5 | jar
6 | uni-resolver-client
7 |
8 |
9 | decentralized-identity
10 | uni-resolver
11 | 0.48-SNAPSHOT
12 |
13 |
14 |
15 | 1.20.0
16 |
17 |
18 |
19 |
20 |
21 | commons-codec
22 | commons-codec
23 | ${commons-codec.version}
24 |
25 |
26 |
27 |
28 |
29 |
30 | decentralized-identity
31 | uni-resolver-core
32 |
33 |
34 | org.apache.httpcomponents
35 | httpclient
36 |
37 |
38 | commons-codec
39 | commons-codec
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/uni-resolver-core/src/main/java/uniresolver/UniResolver.java:
--------------------------------------------------------------------------------
1 | package uniresolver;
2 |
3 | import foundation.identity.did.representations.Representations;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import uniresolver.result.ResolveResult;
7 | import uniresolver.w3c.DIDResolver;
8 |
9 | import java.util.List;
10 | import java.util.Map;
11 | import java.util.Set;
12 |
13 | public interface UniResolver extends DIDResolver {
14 |
15 | public static final String PROPERTIES_MEDIA_TYPE = "application/json";
16 | public static final String METHODS_MEDIA_TYPE = "application/json";
17 | public static final String TEST_IDENTIFIER_MEDIA_TYPE = "application/json";
18 | public static final String TRAITS_MEDIA_TYPE = "application/json";
19 |
20 | static final Logger log = LoggerFactory.getLogger(UniResolver.class);
21 |
22 | @Override public ResolveResult resolve(String didString, Map resolutionOptions) throws ResolutionException;
23 |
24 | default public ResolveResult resolve(String didString) throws ResolutionException {
25 | return this.resolve(didString, Map.of("accept", Representations.DEFAULT_MEDIA_TYPE));
26 | }
27 |
28 | public Map> properties() throws ResolutionException;
29 | public Set methods() throws ResolutionException;
30 | public Map> testIdentifiers() throws ResolutionException;
31 | public Map> traits() throws ResolutionException;
32 | }
33 |
--------------------------------------------------------------------------------
/driver/src/main/java/uniresolver/driver/Driver.java:
--------------------------------------------------------------------------------
1 | package uniresolver.driver;
2 |
3 | import foundation.identity.did.DID;
4 | import foundation.identity.did.DIDURL;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import uniresolver.DereferencingException;
8 | import uniresolver.ResolutionException;
9 | import uniresolver.result.DereferenceResult;
10 | import uniresolver.result.ResolveResult;
11 |
12 | import java.util.Collections;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | public interface Driver {
17 |
18 | public static final String PROPERTIES_MEDIA_TYPE = "application/json";
19 | public static final String TEST_IDENTIFIER_MEDIA_TYPE = "application/json";
20 | public static final String TRAITS_MEDIA_TYPE = "application/json";
21 |
22 | static final Logger log = LoggerFactory.getLogger(Driver.class);
23 |
24 | public ResolveResult resolve(DID did, Map resolutionOptions) throws ResolutionException;
25 |
26 | public DereferenceResult dereference(DIDURL didUrl, Map dereferenceOptions) throws DereferencingException, ResolutionException;
27 |
28 | default public Map properties() throws ResolutionException {
29 | return Collections.emptyMap();
30 | }
31 |
32 | default public List testIdentifiers() throws ResolutionException {
33 | return Collections.emptyList();
34 | }
35 |
36 | default public Map traits() throws ResolutionException {
37 | return Collections.emptyMap();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | 4.0.0
5 | uni-resolver-examples
6 | jar
7 | uni-resolver-examples
8 |
9 | decentralized-identity
10 | uni-resolver
11 | 0.4-SNAPSHOT
12 |
13 |
14 |
15 |
16 | decentralized-identity
17 | uni-resolver-local
18 | compile
19 |
20 |
21 | decentralized-identity
22 | uni-resolver-client
23 | compile
24 |
25 |
26 | decentralized-identity
27 | uni-resolver-driver-did-sov
28 | 0.4-SNAPSHOT
29 | compile
30 |
31 |
32 | decentralized-identity
33 | uni-resolver-driver-did-btcr
34 | 0.1.3-SNAPSHOT
35 | compile
36 |
37 |
38 | org.apache.logging.log4j
39 | log4j-slf4j2-impl
40 | 2.13.3
41 | compile
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ci/docker-build-push/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -l
2 | set -e
3 |
4 | echo "DOCKER BUILD AND PUSH"
5 |
6 | echo "Environment: "
7 | echo "- BUILD_PATH: ${BUILD_PATH}";
8 | echo "- DOCKER_FILE: ${DOCKER_FILE}";
9 | echo "- CONTAINER_TAG: ${CONTAINER_TAG}";
10 | echo "- GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME}";
11 | echo "- GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}";
12 | echo "- GITHUB_REF: ${GITHUB_REF}";
13 | echo "- GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}";
14 | echo "- GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}";
15 | echo "- GITHUB_ACTOR: ${GITHUB_ACTOR}";
16 |
17 | if [[ -z "$GITHUB_EVENT_NAME" ]]; then
18 | echo "Set the GITHUB_EVENT_NAME env variable."
19 | exit 1
20 | fi
21 |
22 | if [[ -z "$GITHUB_EVENT_PATH" ]]; then
23 | echo "Set the GITHUB_EVENT_PATH env variable."
24 | exit 1
25 | fi
26 |
27 | if [[ -z "$GITHUB_REF" ]]; then
28 | echo "Set the GITHUB_REF env variable."
29 | exit 1
30 | fi
31 |
32 | if [ -z "${DOCKER_FILE}" ]
33 | then
34 | echo "No Dockerfile specified. Using default file: Dockerfile"
35 | DOCKER_FILE=Dockerfile
36 | fi
37 |
38 | if [[ -z "$CONTAINER_TAG" ]]; then
39 | echo "Set the CONTAINER_TAG env variable."
40 | exit 1
41 | fi
42 |
43 | ls -al
44 |
45 | if [ -n "${BUILD_PATH}" ]
46 | then
47 | cd ${BUILD_PATH}
48 | fi
49 |
50 | ls -al
51 |
52 | echo "Building container ..."
53 | docker build . -f ${DOCKER_FILE} -t ${CONTAINER_TAG}
54 |
55 | if [ -n "${DOCKER_USERNAME}" ]
56 | then
57 | echo "Pushing container to DockerHub ..."
58 |
59 | docker login -u ${DOCKER_USERNAME} -p ${DOCKER_PASSWORD}
60 |
61 | docker push ${CONTAINER_TAG}
62 | fi
63 |
64 |
--------------------------------------------------------------------------------
/driver/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | uni-resolver-driver
5 | jar
6 | uni-resolver-driver
7 |
8 |
9 | decentralized-identity
10 | uni-resolver
11 | 0.48-SNAPSHOT
12 |
13 |
14 |
15 | 6.1.0
16 | 7.0.2
17 |
18 |
19 |
20 |
21 |
22 | jakarta.servlet
23 | jakarta.servlet-api
24 | ${jakarta.servlet-api.version}
25 |
26 |
27 | org.springframework
28 | spring-web
29 | ${org.springframework-spring-web.version}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | jakarta.servlet
38 | jakarta.servlet-api
39 | provided
40 |
41 |
42 | decentralized-identity
43 | uni-resolver-core
44 |
45 |
46 | org.springframework
47 | spring-web
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/java/uniresolver/web/WebUniResolverApplication.java:
--------------------------------------------------------------------------------
1 | package uniresolver.web;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.boot.builder.SpringApplicationBuilder;
7 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
8 | import org.springframework.context.ApplicationContext;
9 | import org.springframework.context.ApplicationContextAware;
10 | import org.springframework.context.annotation.Bean;
11 | import uniresolver.local.LocalUniDereferencer;
12 | import uniresolver.local.LocalUniResolver;
13 |
14 | @SpringBootApplication
15 | public class WebUniResolverApplication extends SpringBootServletInitializer implements ApplicationContextAware {
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(WebUniResolverApplication.class, args);
19 | }
20 |
21 | private ApplicationContext applicationContext;
22 |
23 | @Override
24 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
25 | return application.sources(WebUniResolverApplication.class);
26 | }
27 |
28 | @Bean(name = "UniResolver")
29 | public LocalUniResolver localUniResolver() {
30 | return new LocalUniResolver();
31 | }
32 |
33 | @Bean(name = "UniDereferencer")
34 | public LocalUniDereferencer localUniDereferencer() {
35 | return new LocalUniDereferencer(this.applicationContext.getBean("UniResolver", LocalUniResolver.class));
36 | }
37 |
38 | @Override
39 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
40 | this.applicationContext = applicationContext;
41 | }
42 | }
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/java/uniresolver/web/WebUniResolverWebServerFactoryCustomizer.java:
--------------------------------------------------------------------------------
1 | package uniresolver.web;
2 |
3 | import org.eclipse.jetty.http.UriCompliance;
4 | import org.eclipse.jetty.server.Connector;
5 | import org.eclipse.jetty.server.HttpConfiguration;
6 | import org.eclipse.jetty.server.HttpConnectionFactory;
7 | import org.eclipse.jetty.server.Server;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;
11 | import org.springframework.boot.web.server.WebServerFactoryCustomizer;
12 | import org.springframework.stereotype.Component;
13 |
14 | @Component
15 | public class WebUniResolverWebServerFactoryCustomizer implements WebServerFactoryCustomizer {
16 |
17 | private static final Logger log = LoggerFactory.getLogger(WebUniResolverWebServerFactoryCustomizer.class);
18 |
19 | @Override
20 | public void customize(JettyServletWebServerFactory factory) {
21 | factory.addServerCustomizers(this::customizeUriCompliance);
22 | }
23 |
24 | private void customizeUriCompliance(Server server) {
25 | if (log.isInfoEnabled()) log.info("Customizing URI compliance: " + server);
26 | for (Connector connector : server.getConnectors()) {
27 | if (log.isInfoEnabled()) log.info("Customizing connector: " + connector);
28 | connector.getConnectionFactories().stream()
29 | .filter(factory -> factory instanceof HttpConnectionFactory)
30 | .forEach(factory -> {
31 | HttpConfiguration httpConfig = ((HttpConnectionFactory) factory).getHttpConfiguration();
32 | httpConfig.setUriCompliance(UriCompliance.UNSAFE);
33 | if (log.isInfoEnabled()) log.info("Set URI compliance: " + httpConfig);
34 | });
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ci/deploy-k8s-aws/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM debian:bookworm-slim
2 |
3 | LABEL "name"="Deployment of the Universal Resolver to a Kubernetes Cluster"
4 | LABEL "maintainer"="Bernhard Fuchs "
5 | LABEL "version"="2.0.0"
6 |
7 | LABEL "com.github.actions.name"="GitHub Action for deploying the Universal Resolver"
8 | LABEL "com.github.actions.description"="Deploys the Universal Resolver to a Kubernetes cluster with smart deployment strategy."
9 | LABEL "com.github.actions.icon"="package"
10 | LABEL "com.github.actions.color"="blue"
11 |
12 | # Install base tools and AWS CLI
13 | RUN apt-get update -y && \
14 | apt-get install -y curl gnupg openssh-client git unzip jq ca-certificates && \
15 | # Install AWS CLI v2
16 | curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
17 | unzip awscliv2.zip && \
18 | ./aws/install && \
19 | rm -rf awscliv2.zip aws && \
20 | # Install AWS IAM Authenticator (latest version compatible with EKS 1.33)
21 | curl -Lso /bin/aws-iam-authenticator https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v0.6.30/aws-iam-authenticator_0.6.30_linux_amd64 && \
22 | chmod +x /bin/aws-iam-authenticator && \
23 | # Note: kubectl will be installed dynamically in entrypoint.sh to match EKS cluster version
24 | # Install yq for YAML parsing
25 | curl -Lso /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 && \
26 | chmod +x /usr/local/bin/yq && \
27 | # Cleanup
28 | apt-get -y clean && apt-get -y autoclean && apt-get -y autoremove && \
29 | rm -rf /var/lib/apt/lists/*
30 |
31 | # Copy deployment scripts
32 | COPY scripts /scripts
33 | RUN chmod +x /scripts/*.sh
34 |
35 | ENTRYPOINT ["/scripts/entrypoint.sh"]
36 |
--------------------------------------------------------------------------------
/ci/get-driver-status/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | echo "#### Driver Status for a Universal Resolver Deployment ####"
4 |
5 | echo "Running with parameters:"
6 | sh -c "echo $*"
7 |
8 | echo "host: $INPUT_HOST"
9 | echo "config: $INPUT_CONFIG"
10 | echo "out folder: $INPUT_OUT"
11 | echo "debug: $INPUT_DEBUG"
12 | echo "keep result: $INPUT_KEEP_RESULT"
13 |
14 | if "$INPUT_DEBUG"; then
15 | echo "Current folder"
16 | pwd
17 | ls -al
18 |
19 | echo "Deployment folder"
20 | ls -al deploy
21 |
22 | echo "Root folder"
23 | ls -al /
24 |
25 | echo "#### Ingress file ####"
26 | cat /github/workspace/deploy/uni-resolver-ingress.yaml
27 | fi
28 |
29 | DATE_WITH_TIME=$(TZ=UTC date "+%Y-%m-%d_%H:%M:%S")
30 | REPORTS_FOLDER="$INPUT_OUT/nightly-run-$DATE_WITH_TIME"
31 | mkdir -p "$REPORTS_FOLDER"
32 |
33 | python --version
34 | python /get-driver-status/get-driver-status.py --host "$INPUT_HOST" --config "$INPUT_CONFIG" --out "$REPORTS_FOLDER"
35 |
36 | echo "Switch to drivers-status-reports branch"
37 | git config --global --add safe.directory /github/workspace
38 | git fetch
39 | git checkout -b driver-status-reports origin/driver-status-reports
40 |
41 | if "$INPUT_KEEP_RESULT";
42 | then
43 | echo "Push result file to repo"
44 | git config --global user.email "admin@danubetech.com"
45 | git config --global user.name "Get driver status workflow"
46 | # Pass driver_status_report to next step in github action
47 | echo "driver_status_report=$(git diff --name-only --staged)" >> "$GITHUB_ENV"
48 | echo "reports_folder=$REPORTS_FOLDER" >> "$GITHUB_ENV"
49 | git add .
50 | git commit -m "Get driver status results"
51 | git push origin driver-status-reports:driver-status-reports
52 | else
53 | cat -b /driver-status-reports/driver-status-*.json
54 | fi
55 |
--------------------------------------------------------------------------------
/driver/src/main/java/uniresolver/driver/util/MediaTypeUtil.java:
--------------------------------------------------------------------------------
1 | package uniresolver.driver.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.http.MediaType;
6 |
7 | import java.util.List;
8 | import java.util.Objects;
9 |
10 | public class MediaTypeUtil {
11 |
12 | private static final Logger log = LoggerFactory.getLogger(MediaTypeUtil.class);
13 |
14 | public static boolean isMediaTypeAcceptable(MediaType acceptMediaType, String mediaTypeString) {
15 | if (mediaTypeString == null) throw new NullPointerException();
16 | MediaType mediaType = MediaType.valueOf(mediaTypeString);
17 | boolean acceptable = false;
18 | if (acceptMediaType.includes(mediaType)) {
19 | acceptable = true;
20 | }
21 | if (acceptMediaType.getType().equals(mediaType.getType()) && mediaType.getSubtype().endsWith("+" + acceptMediaType.getSubtype())) {
22 | acceptable = true;
23 | }
24 | if (! MediaType.ALL.equals(acceptMediaType)) {
25 | if (acceptMediaType.getParameters() != null) {
26 | acceptable &= Objects.equals(acceptMediaType.getParameter("profile"), mediaType.getParameter("profile"));
27 | }
28 | }
29 | if (log.isDebugEnabled()) log.debug("Checking if media type " + mediaType + " is acceptable for " + acceptMediaType + ": " + acceptable);
30 | return acceptable;
31 | }
32 |
33 | public static boolean isMediaTypeAcceptable(List acceptMediaTypes, String mediaTypeString) {
34 | for (MediaType acceptMediaType : acceptMediaTypes) {
35 | if (isMediaTypeAcceptable(acceptMediaType, mediaTypeString)) {
36 | return true;
37 | }
38 | }
39 | return false;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/driver/src/main/java/uniresolver/driver/servlet/InitServlet.java:
--------------------------------------------------------------------------------
1 | package uniresolver.driver.servlet;
2 |
3 | import jakarta.servlet.Servlet;
4 | import jakarta.servlet.ServletConfig;
5 | import jakarta.servlet.ServletException;
6 | import jakarta.servlet.http.HttpServlet;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import uniresolver.driver.Driver;
10 |
11 | import java.lang.reflect.InvocationTargetException;
12 |
13 | public class InitServlet extends HttpServlet implements Servlet {
14 |
15 | private static final Logger log = LoggerFactory.getLogger(InitServlet.class);
16 |
17 | private static Driver driver = null;
18 |
19 | public InitServlet() {
20 |
21 | super();
22 | }
23 |
24 | @SuppressWarnings("unchecked")
25 | @Override
26 | public void init(ServletConfig config) throws ServletException {
27 |
28 | super.init(config);
29 |
30 | if (driver == null) {
31 |
32 | String driverClassName = config.getInitParameter("Driver");
33 | Class extends Driver> driverClass;
34 |
35 | try {
36 |
37 | driverClass = driverClassName == null ? null : (Class extends Driver>) Class.forName(driverClassName);
38 | driver = driverClass == null ? null : driverClass.getConstructor().newInstance();
39 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
40 |
41 | throw new ServletException(ex.getMessage(), ex);
42 | }
43 |
44 | if (driver == null) throw new ServletException("Unable to load driver: (no 'Driver' init parameter)");
45 |
46 | if (log.isInfoEnabled()) log.info("Loaded driver: " + driverClass);
47 | }
48 | }
49 |
50 | public static Driver getDriver() {
51 | return InitServlet.driver;
52 | }
53 |
54 | public static void setDriver(Driver driver) {
55 | InitServlet.driver = driver;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/ci/get-driver-status/README.md:
--------------------------------------------------------------------------------
1 | # universal-resolver-deployment-driver-status
2 |
3 | This tool can be used as a standalone script for testing an existing deployment of the Uni Resolver, it can be integrated as a [github action](https://github.com/features/actions) into a github workflow, or it can be run as docker container.
4 |
5 | ## Run get-driver-status script manually
6 |
7 | python get-driver-status.py --host --config --out --write200 false
8 |
9 | The script needs Python 3 and dependencies listed in the `requirements.txt`.
10 |
11 | Automatic installation of requirements:
12 |
13 | pip install --no-cache-dir -r requirements.txt
14 |
15 | All arguments are optional and default values are aligned with github actions workflow.
16 |
17 | Default values:
18 |
19 | host: https://dev.uniresolver.io
20 | config: /github/workspace/config.json
21 | out: ./
22 | write200: True
23 |
24 |
25 | ## Use action in github workflow
26 |
27 | - name: Get Driver Status
28 | uses: ./ci/driver-status
29 | with:
30 | host: ://
31 | config:
32 | out folder:
33 | debug:
34 | write200:
35 |
36 | Example can be seen in the [uni-resolver workflow configuration](https://github.com/decentralized-identity/universal-resolver/blob/master/.github/workflows/universal-resolver-build-deploy.yml)
37 |
38 | ## Run as docker container
39 | ### Build container with
40 |
41 | docker build -f Dockerfile -t get-driver-status .
42 |
43 | ### Run container with
44 |
45 | docker run -it --rm -e HOST= -e CONFIG_FILE= --name get-driver-status .
46 |
--------------------------------------------------------------------------------
/.github/workflows/kubernetes-deploy-to-cluster.yml:
--------------------------------------------------------------------------------
1 | name: AWS Kubernetes deployment
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout repository
11 | uses: actions/checkout@v4
12 |
13 | - name: Import Secrets
14 | uses: hashicorp/vault-action@v3
15 | with:
16 | url: ${{ secrets.VAULT_ADDR }}
17 | token: ${{ secrets.CI_SECRET_READER_PERIODIC_TOKEN }}
18 | caCertificate: ${{ secrets.VAULTCA }}
19 | secrets: |
20 | ci/data/gh-workflows/universal-resolver-cluster aws-access-key-id | AWS_ACCESS_KEY_ID ;
21 | ci/data/gh-workflows/universal-resolver-cluster aws-secret-access-key | AWS_SECRET_ACCESS_KEY ;
22 | ci/data/gh-workflows/universal-resolver-cluster rpc-url-testnet | RPC_URL_TESTNET ;
23 | ci/data/gh-workflows/universal-resolver-cluster rpc-cert-testnet | RPC_CERT_TESTNET
24 |
25 | - name: Deploy to AWS Kubernetes Cluster
26 | uses: ./ci/deploy-k8s-aws
27 | with:
28 | kube-config-data: ${{ secrets.KUBE_CONFIG_DATA_BASE64_UNI_RESOLVER_PROD }}
29 | aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
30 | aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
31 | rpc-url-testnet: ${{ env.RPC_URL_TESTNET }}
32 | rpc-cert-testnet: ${{ env.RPC_CERT_TESTNET }}
33 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
34 | github-server-url: ${{ github.server_url }}
35 | github-repository: ${{ github.repository }}
36 | github-run-id: ${{ github.run_id }}
37 |
38 | - name: Slack notification
39 | if: failure()
40 | uses: 8398a7/action-slack@v3
41 | with:
42 | status: ${{ job.status }}
43 | fields: repo,commit,action,eventName,ref,workflow
44 | env:
45 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
46 |
--------------------------------------------------------------------------------
/ci/deploy-k8s-aws/scripts/process-env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ################################################################################
4 | # Process Environment Variables
5 | #
6 | # This script creates a Kubernetes ConfigMap from the .env file.
7 | # The ConfigMap is named 'app-config' and can be referenced by deployments
8 | # to inject environment variables into containers.
9 | #
10 | # Prerequisites:
11 | # - kubectl must be configured and authenticated
12 | # - NAMESPACE environment variable must be set
13 | #
14 | # Usage:
15 | # NAMESPACE=uni-resolver ./process-env.sh [path-to-env-file]
16 | #
17 | # Output:
18 | # ConfigMap 'app-config' created/updated in the specified namespace
19 | ################################################################################
20 |
21 | set -e
22 |
23 | # Default .env file location
24 | ENV_FILE="${1:-.env}"
25 |
26 | # Validate namespace is set
27 | if [ -z "$NAMESPACE" ]; then
28 | echo "Error: NAMESPACE environment variable is not set"
29 | exit 1
30 | fi
31 |
32 | echo "Processing environment variables from $ENV_FILE..."
33 |
34 | # Check if .env file exists
35 | if [ -f "$ENV_FILE" ]; then
36 | # Create a ConfigMap from .env file
37 | # Using --dry-run=client to generate YAML without applying it first
38 | kubectl create configmap app-config \
39 | --from-env-file="$ENV_FILE" \
40 | --namespace="$NAMESPACE" \
41 | --dry-run=client -o yaml > configmap.yaml
42 |
43 | # Apply the ConfigMap to the cluster
44 | kubectl apply -f configmap.yaml
45 |
46 | echo "✓ ConfigMap 'app-config' created/updated from $ENV_FILE"
47 | echo " Total environment variables: $(grep -c "=" "$ENV_FILE" 2>/dev/null || echo 0)"
48 | else
49 | echo "Warning: No $ENV_FILE file found, skipping ConfigMap creation"
50 | echo "Deployments will use default environment variables from their Docker images"
51 | fi
52 |
--------------------------------------------------------------------------------
/.github/workflows/archive_lint_reports.yml:
--------------------------------------------------------------------------------
1 | name: Copy Result JSON on Commit
2 |
3 | on:
4 | push:
5 | branches:
6 | - did-lint-reports
7 | paths:
8 | - 'result.json'
9 | workflow_dispatch:
10 |
11 | jobs:
12 | copy-result-json:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout source code
16 | uses: actions/checkout@v4
17 |
18 | - name: Get current timestamp
19 | id: timestamp
20 | uses: nanzm/get-time-action@master
21 | with:
22 | timeZone: UTC
23 | format: 'YYYY-MM-DD-HH-mm-ss'
24 |
25 | - name: Install dependencies
26 | run: sudo apt-get install jq -y
27 |
28 | - name: Configure git user
29 | run: |
30 | git config --global user.name 'Kim Duffy'
31 | git config --global user.email 'kimdhamilton@gmail.com'
32 |
33 | - name: Copy result.json with timestamp
34 | run: |
35 | cp result.json result_${{ steps.timestamp.outputs.time }}.json
36 | jq . result_${{ steps.timestamp.outputs.time }}.json > tmp.json && mv tmp.json result_${{ steps.timestamp.outputs.time }}.json
37 |
38 | - name: Push to target repository
39 | env:
40 | REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
41 | run: |
42 | git clone https://x-access-token:${REPO_ACCESS_TOKEN}@github.com/decentralized-identity/universal-resolver-lint-dashboard.git
43 | cd universal-resolver-lint-dashboard
44 | git checkout -b new-result || git checkout new-result
45 | git branch --set-upstream-to=origin/new-result new-result
46 | git pull
47 | mv ../result_${{ steps.timestamp.outputs.time }}.json .
48 | git add result_${{ steps.timestamp.outputs.time }}.json
49 | git commit -m "Add new result file"
50 | git push -u origin new-result
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ci/deploy-k8s-aws/scripts/parse-compose.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ################################################################################
4 | # Parse docker-compose.yml
5 | #
6 | # This script parses the docker-compose.yml file and extracts service
7 | # information into a JSON file (services.json) for further processing.
8 | #
9 | # Extracted information:
10 | # - Service name
11 | # - Container image (with tag)
12 | # - Exposed ports
13 | # - Environment variables
14 | # - Environment file references
15 | # - Volumes
16 | # - Command
17 | # - Restart policy
18 | #
19 | # Usage:
20 | # ./parse-compose.sh [path-to-docker-compose.yml]
21 | #
22 | # Output:
23 | # services.json - JSON array containing service definitions
24 | ################################################################################
25 |
26 | set -e
27 |
28 | # Default docker-compose file location
29 | COMPOSE_FILE="${1:-docker-compose.yml}"
30 |
31 | # Validate that docker-compose.yml exists
32 | if [ ! -f "$COMPOSE_FILE" ]; then
33 | echo "Error: docker-compose.yml not found at $COMPOSE_FILE"
34 | exit 1
35 | fi
36 |
37 | echo "Parsing $COMPOSE_FILE..."
38 |
39 | # Extract services information using yq
40 | # For each service, create a JSON object with all relevant fields
41 | yq eval -o=json '.services | to_entries | .[] | {
42 | "name": .key,
43 | "image": .value.image,
44 | "ports": .value.ports,
45 | "environment": .value.environment,
46 | "env_file": .value.env_file,
47 | "volumes": .value.volumes,
48 | "command": .value.command,
49 | "restart": .value.restart
50 | }' "$COMPOSE_FILE" > services.json
51 |
52 | # Validate JSON output
53 | if [ ! -s services.json ]; then
54 | echo "Error: Failed to parse services from docker-compose.yml"
55 | exit 1
56 | fi
57 |
58 | echo "Services parsed successfully:"
59 | cat services.json
60 |
61 | echo ""
62 | echo "Total services found: $(cat services.json | jq -s 'length')"
63 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/java/uniresolver/web/servlet/MethodsServlet.java:
--------------------------------------------------------------------------------
1 | package uniresolver.web.servlet;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import uniresolver.UniResolver;
9 | import uniresolver.web.WebUniResolver;
10 |
11 | import java.io.IOException;
12 | import java.util.Set;
13 |
14 | public class MethodsServlet extends WebUniResolver {
15 |
16 | protected static final Logger log = LoggerFactory.getLogger(MethodsServlet.class);
17 |
18 | private static final ObjectMapper objectMapper = new ObjectMapper();
19 |
20 | @Override
21 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
22 |
23 | // read request
24 |
25 | request.setCharacterEncoding("UTF-8");
26 | response.setCharacterEncoding("UTF-8");
27 |
28 | if (log.isInfoEnabled()) log.info("Incoming request.");
29 |
30 | // execute the request
31 |
32 | Set methods;
33 | String methodsString;
34 |
35 | try {
36 |
37 | methods = this.methods();
38 | methodsString = methods == null ? null : objectMapper.writeValueAsString(methods);
39 | } catch (Exception ex) {
40 |
41 | if (log.isWarnEnabled()) log.warn("Resolver reported: " + ex.getMessage(), ex);
42 | ServletUtil.sendResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Resolver reported: " + ex.getMessage());
43 | return;
44 | }
45 |
46 | if (log.isInfoEnabled()) log.info("Methods: " + methods);
47 |
48 | // no result?
49 |
50 | if (methods == null) {
51 |
52 | ServletUtil.sendResponse(response, HttpServletResponse.SC_NOT_FOUND, "No methods.");
53 | return;
54 | }
55 |
56 | // write result
57 |
58 | ServletUtil.sendResponse(response, HttpServletResponse.SC_OK, UniResolver.METHODS_MEDIA_TYPE, methodsString);
59 | }
60 | }
--------------------------------------------------------------------------------
/uni-resolver-local/src/main/java/uniresolver/local/extensions/ResolverExtension.java:
--------------------------------------------------------------------------------
1 | package uniresolver.local.extensions;
2 |
3 | import foundation.identity.did.DID;
4 | import uniresolver.ResolutionException;
5 | import uniresolver.local.LocalUniResolver;
6 | import uniresolver.result.ResolveResult;
7 |
8 | import java.lang.annotation.ElementType;
9 | import java.lang.annotation.Retention;
10 | import java.lang.annotation.RetentionPolicy;
11 | import java.lang.annotation.Target;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | public interface ResolverExtension {
16 |
17 | @Retention(RetentionPolicy.RUNTIME)
18 | @Target(ElementType.TYPE)
19 | @interface ExtensionStage {
20 | String value();
21 | }
22 |
23 | @FunctionalInterface
24 | interface ExtensionFunction {
25 | ExtensionStatus apply(E extension) throws ResolutionException;
26 | }
27 |
28 | @ExtensionStage("beforeResolve")
29 | interface BeforeResolveResolverExtension extends ResolverExtension {
30 | default ExtensionStatus beforeResolve(DID did, Map resolutionOptions, ResolveResult resolveResult, Map executionState, LocalUniResolver localUniResolver) throws ResolutionException {
31 | return null;
32 | }
33 | }
34 |
35 | @ExtensionStage("afterResolve")
36 | interface AfterResolveResolverExtension extends ResolverExtension {
37 | default ExtensionStatus afterResolve(DID did, Map resolutionOptions, ResolveResult resolveResult, Map executionState, LocalUniResolver localUniResolver) throws ResolutionException {
38 | return null;
39 | }
40 | }
41 |
42 | abstract class AbstractResolverExtension implements BeforeResolveResolverExtension, AfterResolveResolverExtension {
43 | }
44 |
45 | static List extensionClassNames(List extends ResolverExtension> extensions) {
46 | return extensions.stream().map(e -> e.getClass().getSimpleName()).toList();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/java/uniresolver/web/servlet/TraitsServlet.java:
--------------------------------------------------------------------------------
1 | package uniresolver.web.servlet;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import uniresolver.UniResolver;
9 | import uniresolver.web.WebUniResolver;
10 |
11 | import java.io.IOException;
12 | import java.util.Map;
13 |
14 | public class TraitsServlet extends WebUniResolver {
15 |
16 | protected static final Logger log = LoggerFactory.getLogger(TraitsServlet.class);
17 |
18 | private static final ObjectMapper objectMapper = new ObjectMapper();
19 |
20 | @Override
21 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
22 |
23 | // read request
24 |
25 | request.setCharacterEncoding("UTF-8");
26 | response.setCharacterEncoding("UTF-8");
27 |
28 | if (log.isInfoEnabled()) log.info("Incoming request.");
29 |
30 | // execute the request
31 |
32 | Map> traits;
33 | String traitsString;
34 |
35 | try {
36 |
37 | traits = this.traits();
38 | traitsString = traits == null ? null : objectMapper.writeValueAsString(traits);
39 | } catch (Exception ex) {
40 |
41 | if (log.isWarnEnabled()) log.warn("Resolver reported: " + ex.getMessage(), ex);
42 | ServletUtil.sendResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Resolver reported: " + ex.getMessage());
43 | return;
44 | }
45 |
46 | if (log.isInfoEnabled()) log.info("Traits: " + traits);
47 |
48 | // no result?
49 |
50 | if (traits == null) {
51 |
52 | ServletUtil.sendResponse(response, HttpServletResponse.SC_NOT_FOUND, "No traits.");
53 | return;
54 | }
55 |
56 | // write result
57 |
58 | ServletUtil.sendResponse(response, HttpServletResponse.SC_OK, UniResolver.TRAITS_MEDIA_TYPE, traitsString);
59 | }
60 | }
--------------------------------------------------------------------------------
/ci/setup-aws-route53/set-alias-dev.uniresolver.io.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 |
4 | # === inputs you can tweak ===
5 | HZ_ID="Z07034832165V2JXMP0FS" # Hosted Zone ID for dev.uniresolver.io (from your CLI output)
6 | RECORD_NAME="dev.uniresolver.io."
7 | ALB_DNS="k8s-uniresol-uniresol-01e0b1f895-139924821.us-east-2.elb.amazonaws.com"
8 | AWS_REGION="us-east-2" # Region of the ALB
9 |
10 | # === derive the ALB's Canonical Hosted Zone ID (safer than hardcoding) ===
11 | ALB_ZONE_ID="$(aws elbv2 describe-load-balancers \
12 | --region "$AWS_REGION" \
13 | --query "LoadBalancers[?DNSName=='${ALB_DNS}'].CanonicalHostedZoneId | [0]" \
14 | --output text)"
15 |
16 | if [[ -z "$ALB_ZONE_ID" || "$ALB_ZONE_ID" == "None" ]]; then
17 | echo "ERROR: Could not resolve ALB CanonicalHostedZoneId for $ALB_DNS in $AWS_REGION"
18 | exit 1
19 | fi
20 |
21 | echo "Using ALB DNS: $ALB_DNS"
22 | echo "ALB Hosted Zone ID: $ALB_ZONE_ID"
23 | echo "Target record: $RECORD_NAME (zone $HZ_ID)"
24 |
25 | # === build the change batch payload ===
26 | CHANGE_BATCH="$(cat <> properties;
33 | String propertiesString;
34 |
35 | try {
36 |
37 | properties = this.properties();
38 | propertiesString = properties == null ? null : objectMapper.writeValueAsString(properties);
39 | } catch (Exception ex) {
40 |
41 | if (log.isWarnEnabled()) log.warn("Resolver reported: " + ex.getMessage(), ex);
42 | ServletUtil.sendResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Resolver reported: " + ex.getMessage());
43 | return;
44 | }
45 |
46 | if (log.isInfoEnabled()) log.info("Properties: " + properties);
47 |
48 | // no result?
49 |
50 | if (properties == null) {
51 |
52 | ServletUtil.sendResponse(response, HttpServletResponse.SC_NOT_FOUND, "No properties.");
53 | return;
54 | }
55 |
56 | // write result
57 |
58 | ServletUtil.sendResponse(response, HttpServletResponse.SC_OK, UniResolver.PROPERTIES_MEDIA_TYPE, propertiesString);
59 | }
60 | }
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
12 |
13 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/java/uniresolver/web/servlet/TestIdentifiersServlet.java:
--------------------------------------------------------------------------------
1 | package uniresolver.web.servlet;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import uniresolver.UniResolver;
9 | import uniresolver.web.WebUniResolver;
10 |
11 | import java.io.IOException;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | public class TestIdentifiersServlet extends WebUniResolver {
16 |
17 | protected static final Logger log = LoggerFactory.getLogger(TestIdentifiersServlet.class);
18 |
19 | private static final ObjectMapper objectMapper = new ObjectMapper();
20 |
21 | @Override
22 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
23 |
24 | // read request
25 |
26 | request.setCharacterEncoding("UTF-8");
27 | response.setCharacterEncoding("UTF-8");
28 |
29 | if (log.isInfoEnabled()) log.info("Incoming request.");
30 |
31 | // execute the request
32 |
33 | Map> testIdentifiers;
34 | String testIdentifiersString;
35 |
36 | try {
37 |
38 | testIdentifiers = this.testIdentifiers();
39 | testIdentifiersString = testIdentifiers == null ? null : objectMapper.writeValueAsString(testIdentifiers);
40 | } catch (Exception ex) {
41 |
42 | if (log.isWarnEnabled()) log.warn("Resolver reported: " + ex.getMessage(), ex);
43 | ServletUtil.sendResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Resolver reported: " + ex.getMessage());
44 | return;
45 | }
46 |
47 | if (log.isInfoEnabled()) log.info("Test identifiers: " + testIdentifiers);
48 |
49 | // no result?
50 |
51 | if (testIdentifiers == null) {
52 |
53 | ServletUtil.sendResponse(response, HttpServletResponse.SC_NOT_FOUND, "No test identifiers.");
54 | return;
55 | }
56 |
57 | // write result
58 |
59 | ServletUtil.sendResponse(response, HttpServletResponse.SC_OK, UniResolver.TEST_IDENTIFIER_MEDIA_TYPE, testIdentifiersString);
60 | }
61 | }
--------------------------------------------------------------------------------
/docs/java-components.md:
--------------------------------------------------------------------------------
1 | # Universal Resolver — Java Components
2 |
3 | This is a Java implementation of a Universal Resolver. See [universal-resolver](https://github.com/decentralized-identity/universal-resolver/) for a general introduction to Universal Resolvers and drivers.
4 |
5 | ## Build (native Java)
6 |
7 | Maven build:
8 |
9 | mvn clean install
10 |
11 | ## Local Resolver
12 |
13 | You can use a [Local Resolver](https://github.com/decentralized-identity/universal-resolver/tree/main/uni-resolver-client) in your Java project that invokes drivers locally (either directly via their JAVA API or via a Docker REST API).
14 |
15 | Dependency:
16 |
17 |
18 | decentralized-identity
19 | uni-resolver-local
20 | 0.1-SNAPSHOT
21 |
22 |
23 | [Example Use](https://github.com/decentralized-identity/universal-resolver/blob/main/examples/src/main/java/uniresolver/examples/TestLocalUniResolver.java):
24 |
25 | ## Web Resolver
26 |
27 | You can deploy a [Web Resolver](https://github.com/decentralized-identity/universal-resolver/tree/main/uni-resolver-web) that can be called by clients and invokes drivers locally (either directly via their JAVA API or via a Docker REST API).
28 |
29 | See the [Example Configuration](https://github.com/decentralized-identity/universal-resolver/blob/main/uni-resolver-web/src/main/webapp/WEB-INF/applicationContext.xml).
30 |
31 | How to run:
32 |
33 | mvn jetty:run
34 |
35 | ## Client Resolver
36 |
37 | You can use a [Client Resolver](https://github.com/decentralized-identity/universal-resolver/tree/main/uni-resolver-client) in your Java project that calls a remote Web Resolver.
38 |
39 | Dependency:
40 |
41 |
42 | decentralized-identity
43 | uni-resolver-client
44 | 0.1-SNAPSHOT
45 |
46 |
47 | [Example Use](https://github.com/decentralized-identity/universal-resolver/blob/main/examples/src/main/java/uniresolver/examples/TestClientUniResolver.java):
48 |
49 | ## About
50 |
51 | Decentralized Identity Foundation - http://identity.foundation/
52 |
--------------------------------------------------------------------------------
/driver/src/main/java/uniresolver/driver/servlet/PropertiesServlet.java:
--------------------------------------------------------------------------------
1 | package uniresolver.driver.servlet;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import jakarta.servlet.Servlet;
5 | import jakarta.servlet.http.HttpServlet;
6 | import jakarta.servlet.http.HttpServletRequest;
7 | import jakarta.servlet.http.HttpServletResponse;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import uniresolver.driver.Driver;
11 |
12 | import java.io.IOException;
13 | import java.util.Map;
14 |
15 | public class PropertiesServlet extends HttpServlet implements Servlet {
16 |
17 | private static final Logger log = LoggerFactory.getLogger(PropertiesServlet.class);
18 |
19 | private static final ObjectMapper objectMapper = new ObjectMapper();
20 |
21 | public PropertiesServlet() {
22 | super();
23 | }
24 |
25 | @Override
26 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
27 |
28 | // read request
29 |
30 | request.setCharacterEncoding("UTF-8");
31 | response.setCharacterEncoding("UTF-8");
32 |
33 | if (log.isInfoEnabled()) log.info("Incoming request.");
34 |
35 | // get properties
36 |
37 | Map properties;
38 | String propertiesString;
39 |
40 | try {
41 | properties = InitServlet.getDriver() == null ? null : InitServlet.getDriver().properties();
42 | propertiesString = properties == null ? null : objectMapper.writeValueAsString(properties);
43 | } catch (Exception ex) {
44 | if (log.isWarnEnabled()) log.warn("Properties problem: " + ex.getMessage(), ex);
45 | ServletUtil.sendResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Properties problem: " + ex.getMessage());
46 | return;
47 | }
48 |
49 | if (log.isInfoEnabled()) log.info("Properties: " + properties);
50 |
51 | // no properties?
52 |
53 | if (properties == null) {
54 | ServletUtil.sendResponse(response, HttpServletResponse.SC_NOT_FOUND, "No properties.");
55 | return;
56 | }
57 |
58 | // write properties
59 |
60 | ServletUtil.sendResponse(response, HttpServletResponse.SC_OK, Driver.PROPERTIES_MEDIA_TYPE, propertiesString);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/examples/src/main/java/uniresolver/examples/w3ctestsuite/TestIdentifier.java:
--------------------------------------------------------------------------------
1 | package uniresolver.examples.w3ctestsuite;
2 |
3 | import foundation.identity.did.DID;
4 | import foundation.identity.did.DIDURL;
5 | import foundation.identity.did.parameters.Parameters;
6 | import uniresolver.ResolutionException;
7 | import uniresolver.client.ClientUniResolver;
8 | import uniresolver.result.ResolveResult;
9 |
10 | import java.net.URLEncoder;
11 | import java.nio.charset.StandardCharsets;
12 | import java.util.ArrayList;
13 | import java.util.LinkedHashMap;
14 | import java.util.List;
15 | import java.util.Map;
16 |
17 | public class TestIdentifier {
18 |
19 | static final List dids = new ArrayList<>();
20 |
21 | static final Map didParameters = new LinkedHashMap<>();
22 |
23 | public static void main(String[] args) throws Exception {
24 |
25 | DID did = DID.fromString("did:sov:WRfXPg8dantKVubE3HX8pw");
26 | dids.add(did.toString());
27 |
28 | DIDURL didUrl1 = DIDURL.fromString(did + "?" + Parameters.DID_URL_PARAMETER_SERVICE + "=" + "files" + "&" + Parameters.DID_URL_PARAMETER_RELATIVEREF + "=" + URLEncoder.encode("/myresume/doc?version=latest#intro", StandardCharsets.UTF_8));
29 | DIDURL didUrl2 = DIDURL.fromString(did + "?" + Parameters.DID_URL_PARAMETER_HL + "=" + "zQmWvQxTqbG2Z9HPJgG57jjwR154cKhbtJenbyYTWkjgF3e");
30 | DIDURL didUrl3 = DIDURL.fromString(did + "?" + Parameters.DID_URL_PARAMETER_VERSIONID + "=" + "4");
31 | DIDURL didUrl4 = DIDURL.fromString(did + "?" + Parameters.DID_URL_PARAMETER_VERSIONTIME + "=" + "2016-10-17T02:41:00Z");
32 |
33 | didParameters.put(Parameters.DID_URL_PARAMETER_SERVICE.toString(), didUrl1.toString());
34 | didParameters.put(Parameters.DID_URL_PARAMETER_RELATIVEREF.toString(), didUrl1.toString());
35 | didParameters.put(Parameters.DID_URL_PARAMETER_HL.toString(), didUrl2.toString());
36 | didParameters.put(Parameters.DID_URL_PARAMETER_VERSIONID.toString(), didUrl3.toString());
37 | didParameters.put(Parameters.DID_URL_PARAMETER_VERSIONTIME.toString(), didUrl4.toString());
38 |
39 | System.out.println(TestSuiteUtil.makeIdentifierTestSuiteReport("sov", dids, didParameters));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Maven and Docker release
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | release_type:
7 | description: 'Major, Minor or Patch release'
8 | type: choice
9 | required: true
10 | default: 'minor'
11 | options:
12 | - "major"
13 | - "minor"
14 | - "patch"
15 |
16 | jobs:
17 | maven-release:
18 | uses: danubetech/workflows/.github/workflows/maven-release.yml@main
19 | with:
20 | MAVEN_REPO_SERVER_ID: 'danubetech-maven-releases'
21 | RELEASE_TYPE: ${{ github.event.inputs.release_type }}
22 | secrets:
23 | VAULT_ADDR: ${{ secrets.VAULT_ADDR }}
24 | CI_SECRET_READER_PERIODIC_TOKEN: ${{ secrets.CI_SECRET_READER_PERIODIC_TOKEN }}
25 | VAULTCA: ${{ secrets.VAULTCA }}
26 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
27 |
28 | docker-release:
29 | needs: maven-release
30 | uses: danubetech/workflows/.github/workflows/maven-triggered-docker-release.yml@main
31 | with:
32 | GLOBAL_IMAGE_NAME: universalresolver/uni-resolver-web
33 | GLOBAL_REPO_NAME: docker.io
34 | GLOBAL_FRAMEWORK: triggered
35 | PATH_TO_DOCKERFILE: uni-resolver-web/docker/Dockerfile
36 | secrets:
37 | VAULT_ADDR: ${{ secrets.VAULT_ADDR }}
38 | CI_SECRET_READER_PERIODIC_TOKEN: ${{ secrets.CI_SECRET_READER_PERIODIC_TOKEN }}
39 | VAULTCA: ${{ secrets.VAULTCA }}
40 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
41 |
42 | docker-release-multi-arch:
43 | needs: docker-release
44 | if: github.ref == 'refs/heads/main'
45 | uses: ./.github/workflows/docker-multi-arch.yml
46 | with:
47 | GLOBAL_FRAMEWORK: maven
48 | GLOBAL_IMAGE_NAME: universalresolver/uni-resolver-web
49 | GLOBAL_REPO_NAME: docker.io
50 | IS_RELEASE: true
51 | PATH_TO_DOCKERFILE: uni-resolver-web/docker/Dockerfile
52 | RELEASE_TYPE: ${{ github.event.inputs.release_type }}
53 | secrets:
54 | CI_SECRET_READER_PERIODIC_TOKEN: ${{ secrets.CI_SECRET_READER_PERIODIC_TOKEN }}
55 | VAULT_ADDR: ${{ secrets.VAULT_ADDR }}
56 | VAULTCA: ${{ secrets.VAULTCA }}
57 |
--------------------------------------------------------------------------------
/ci/run-did-test-suite/README.md:
--------------------------------------------------------------------------------
1 | # run-did-test-suite action
2 |
3 | Developed with Node 14.x and without guarantee of backwards compatibility.
4 |
5 | ## env variables
6 | `MODE`:
7 | - `server`(default) Run against a did-test-suite server
8 | - `local` Create local files
9 |
10 | `DRIVER_STATUS_REPORT`:
11 | - Path to file, generated by [get-driver-status](https://github.com/decentralized-identity/universal-resolver/tree/driver-status-reporting/ci/get-driver-status) action
12 |
13 | `OUTPUT_PATH`:
14 | - In `server` mode: Path to write the did-test-suite report
15 | - In `local` mode: Path to write the created files
16 |
17 | `HOST`:
18 | - Only for `server` mode and required
19 | - Full url of deployed did-test-suite endpoint e.g. `https://did-test-suite.uniresolver.io/test-suite-manager/generate-report`
20 |
21 | `GENERATE_DEFAULT_FILE`:
22 | - Only for `local` mode and optional
23 | - If `true` script automatically creates a `default.js` file with all the resolver related files in the `OUTPUT_PATH`
24 |
25 | ### Server mode to run against hosted did-test-suite example
26 |
27 | ```bash
28 | node index.js --DRIVER_STATUS_REPORT=/driver-status-2021-05-19_15-08-15-UTC.json --HOST=https://did-test-suite.uniresolver.io/test-suite-manager/generate-report
29 | ```
30 |
31 | ### Local mode to create manual files example
32 |
33 | ```bash
34 | node index.js --MODE=local --DRIVER_STATUS_REPORT=/driver-status-2021-05-19_15-08-15-UTC.json --OUTPUT_PATH= --GENERATE_DEFAULT_FILE=true
35 | ```
36 |
37 | ### Github action example
38 |
39 | **Note:** Env variables for `driver_status_report` and `reports_folder` are set by previous step in this case. See [example](https://github.com/decentralized-identity/universal-resolver/blob/ccbbbf17946ff62b53f647734c382dc460661659/ci/get-driver-status/entrypoint.sh#L43) in `get-driver-status` action.
40 |
41 | ```yaml
42 | - name: Run did-test-suite
43 | uses: ./ci/run-did-test-suite
44 | with:
45 | host: https://did-test-suite.uniresolver.io/test-suite-manager/generate-report
46 | driver_status_report: ${{ env.driver_status_report }}
47 | reports_folder: ${{ env.reports_folder }}
48 | ```
49 |
--------------------------------------------------------------------------------
/uni-resolver-web/src/main/java/uniresolver/web/servlet/ServletUtil.java:
--------------------------------------------------------------------------------
1 | package uniresolver.web.servlet;
2 |
3 | import jakarta.servlet.http.HttpServletResponse;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 | import java.nio.charset.StandardCharsets;
10 | import java.util.Map;
11 |
12 | public class ServletUtil {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(ServletUtil.class);
15 |
16 | public static void sendResponse(HttpServletResponse response, int status, Map headers, byte[] body) throws IOException {
17 |
18 | if (log.isInfoEnabled()) log.info("Sending response with status " + status + " and headers " + headers + " and body (" + (body == null ? null : body.length) + ")");
19 |
20 | response.setStatus(status);
21 | if (headers != null) for (Map.Entry header : headers.entrySet()) response.setHeader(header.getKey(), header.getValue());
22 | response.setHeader("Access-Control-Allow-Origin", "*");
23 |
24 | if (body != null) {
25 | OutputStream outputStream = response.getOutputStream();
26 | outputStream.write(body);
27 | outputStream.flush();
28 | outputStream.close();
29 | }
30 |
31 | response.flushBuffer();
32 | }
33 |
34 | public static void sendResponse(HttpServletResponse response, int status, String contentType, byte[] body) throws IOException {
35 | sendResponse(response, status, Map.of("Content-Type", contentType), body);
36 | }
37 |
38 | public static void sendResponse(HttpServletResponse response, int status, String contentType, String body) throws IOException {
39 | sendResponse(response, status, Map.of("Content-Type", contentType), body == null ? null : body.getBytes(StandardCharsets.UTF_8));
40 | }
41 |
42 | public static void sendResponse(HttpServletResponse response, int status, byte[] body) throws IOException {
43 | sendResponse(response, status, (Map) null, body);
44 | }
45 |
46 | public static void sendResponse(HttpServletResponse response, int status, String body) throws IOException {
47 | sendResponse(response, status, (Map) null, body == null ? null : body.getBytes(StandardCharsets.UTF_8));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ci/deploy-k8s-aws/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Deploy Universal Resolver to AWS Kubernetes'
2 | description: 'Deploy the Universal Resolver to AWS EKS cluster using smart deployment strategy'
3 | author: 'Bernhard Fuchs '
4 |
5 | branding:
6 | icon: 'package'
7 | color: 'blue'
8 |
9 | inputs:
10 | kube-config-data:
11 | description: 'Base64-encoded Kubernetes configuration data'
12 | required: true
13 | aws-access-key-id:
14 | description: 'AWS Access Key ID for authentication'
15 | required: true
16 | aws-secret-access-key:
17 | description: 'AWS Secret Access Key for authentication'
18 | required: true
19 | namespace:
20 | description: 'Kubernetes namespace to deploy to'
21 | required: false
22 | default: 'uni-resolver'
23 | rpc-url-testnet:
24 | description: 'RPC URL for driver-did-btcr (optional)'
25 | required: false
26 | default: ''
27 | rpc-cert-testnet:
28 | description: 'RPC certificate for driver-did-btcr (optional)'
29 | required: false
30 | default: ''
31 | slack-webhook-url:
32 | description: 'Slack webhook URL for notifications (optional)'
33 | required: false
34 | default: ''
35 | github-server-url:
36 | description: 'GitHub server URL (automatically set by GitHub Actions)'
37 | required: false
38 | default: 'https://github.com'
39 | github-repository:
40 | description: 'GitHub repository (automatically set by GitHub Actions)'
41 | required: false
42 | default: ''
43 | github-run-id:
44 | description: 'GitHub run ID (automatically set by GitHub Actions)'
45 | required: false
46 | default: ''
47 |
48 | runs:
49 | using: 'docker'
50 | image: 'Dockerfile'
51 | env:
52 | KUBE_CONFIG_DATA: ${{ inputs.kube-config-data }}
53 | AWS_ACCESS_KEY_ID: ${{ inputs.aws-access-key-id }}
54 | AWS_SECRET_ACCESS_KEY: ${{ inputs.aws-secret-access-key }}
55 | NAMESPACE: ${{ inputs.namespace }}
56 | RPC_URL_TESTNET: ${{ inputs.rpc-url-testnet }}
57 | RPC_CERT_TESTNET: ${{ inputs.rpc-cert-testnet }}
58 | SLACK_WEBHOOK_URL: ${{ inputs.slack-webhook-url }}
59 | GITHUB_SERVER_URL: ${{ inputs.github-server-url }}
60 | GITHUB_REPOSITORY: ${{ inputs.github-repository }}
61 | GITHUB_RUN_ID: ${{ inputs.github-run-id }}
62 |
--------------------------------------------------------------------------------
/driver/src/main/java/uniresolver/driver/servlet/ServletUtil.java:
--------------------------------------------------------------------------------
1 | package uniresolver.driver.servlet;
2 |
3 | import jakarta.servlet.http.HttpServletResponse;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 | import java.io.PrintWriter;
10 | import java.util.Map;
11 |
12 | public class ServletUtil {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(ServletUtil.class);
15 |
16 | static void sendResponse(HttpServletResponse response, int status, Map headers, Object body) throws IOException {
17 |
18 | if (log.isDebugEnabled()) log.debug("Sending response with status " + status + " and headers " + headers + " and body (" + (body == null ? null : body.getClass()) + ")");
19 |
20 | response.setStatus(status);
21 | if (headers != null) for (Map.Entry header : headers.entrySet()) response.setHeader(header.getKey(), header.getValue());
22 | response.setHeader("Access-Control-Allow-Origin", "*");
23 |
24 | if (body instanceof String) {
25 |
26 | PrintWriter printWriter = response.getWriter();
27 | printWriter.write((String) body);
28 | printWriter.flush();
29 | printWriter.close();
30 | } else if (body instanceof byte[]) {
31 |
32 | OutputStream outputStream = response.getOutputStream();
33 | outputStream.write((byte[]) body);
34 | outputStream.flush();
35 | outputStream.close();
36 | } else if (body != null) {
37 |
38 | PrintWriter printWriter = response.getWriter();
39 | printWriter.write(body.toString());
40 | printWriter.flush();
41 | printWriter.close();
42 | }
43 |
44 | response.flushBuffer();
45 | }
46 |
47 | static void sendResponse(HttpServletResponse response, int status, Map headers) throws IOException {
48 |
49 | sendResponse(response, status, headers, null);
50 | }
51 |
52 | static void sendResponse(HttpServletResponse response, int status, String contentType, Object body) throws IOException {
53 |
54 | sendResponse(response, status, Map.of("Content-Type", contentType), body);
55 | }
56 |
57 | static void sendResponse(HttpServletResponse response, int status, Object body) throws IOException {
58 |
59 | sendResponse(response, status, (Map) null, body);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/examples/src/main/java/uniresolver/examples/w3ctestsuite/TestDIDResolution.java:
--------------------------------------------------------------------------------
1 | package uniresolver.examples.w3ctestsuite;
2 |
3 | import uniresolver.ResolutionException;
4 | import uniresolver.client.ClientUniResolver;
5 | import uniresolver.result.ResolveResult;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | public class TestDIDResolution {
12 |
13 | static final Map> expectedOutcomes = Map.of(
14 | "defaultOutcome", List.of(0, 1),
15 | "notFoundErrorOutcome", List.of(2),
16 | "invalidDidErrorOutcome", List.of(3)
17 | );
18 |
19 | static final List function = List.of(
20 | "resolve",
21 | "resolveRepresentation",
22 | "resolve",
23 | "resolve"
24 | );
25 |
26 | static final List didString = List.of(
27 | "did:sov:WRfXPg8dantKVubE3HX8pw",
28 | "did:sov:WRfXPg8dantKVubE3HX8pw",
29 | "did:sov:0000000000000000000000",
30 | "did:sov:danube:_$::"
31 | );
32 |
33 | static final List