├── .circleci ├── config.yml └── install_hub.sh ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── AUDIT.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── __integrations__ ├── credentials │ └── VerifiableCredential.test.js └── fixtures │ ├── correct │ ├── Credential │ │ ├── Address.json │ │ ├── CivicBasic.json │ │ └── GenericId.json │ ├── Identity │ │ ├── dateOfBirth.json │ │ ├── dateOfExpiry.json │ │ ├── dateOfIssue.json │ │ ├── firstName.json │ │ ├── givenName.json │ │ ├── name.first.json │ │ ├── name.json │ │ ├── name.last.json │ │ ├── name.middle.json │ │ ├── name.nickname.json │ │ └── name.username.json │ ├── Meta │ │ ├── expirationDate.json │ │ ├── issuanceDate.json │ │ └── issuer.json │ ├── Random │ │ └── node.json │ ├── Type │ │ ├── address.city.json │ │ ├── address.country.json │ │ ├── address.county.json │ │ ├── address.json │ │ ├── address.state.json │ │ ├── address.street.json │ │ ├── address.unit.json │ │ ├── address.zipCode.json │ │ ├── date.json │ │ ├── day.json │ │ ├── documentNumber.json │ │ ├── documentType.json │ │ ├── email.domain.json │ │ ├── email.json │ │ ├── email.user.json │ │ ├── image.image.json │ │ ├── image.json │ │ ├── image.md5.json │ │ ├── month.json │ │ ├── phone.countryCode.json │ │ ├── phone.json │ │ ├── phone.number.json │ │ ├── shortToken.json │ │ └── year.json │ └── Verify │ │ ├── email.token.json │ │ └── phoneNumber.token.json │ └── incorrect │ ├── Credential │ ├── Address.json │ ├── CivicBasic.json │ └── GenericId.json │ ├── Identity │ ├── dateOfBirth.json │ ├── dateOfExpiry.json │ ├── dateOfIssue.json │ ├── firstName.json │ ├── givenName.json │ ├── name.first.json │ ├── name.json │ ├── name.last.json │ ├── name.middle.json │ ├── name.nickname.json │ └── name.username.json │ ├── Meta │ ├── expirationDate.json │ ├── issuanceDate.json │ └── issuer.json │ ├── Random │ └── node.json │ ├── Type │ ├── address.city.json │ ├── address.country.json │ ├── address.county.json │ ├── address.json │ ├── address.state.json │ ├── address.street.json │ ├── address.unit.json │ ├── address.zipCode.json │ ├── date.json │ ├── day.json │ ├── documentNumber.json │ ├── documentType.json │ ├── email.domain.json │ ├── email.json │ ├── email.user.json │ ├── image.image.json │ ├── image.json │ ├── image.md5.json │ ├── month.json │ ├── phone.countryCode.json │ ├── phone.json │ ├── phone.number.json │ ├── shortToken.json │ └── year.json │ └── Verify │ ├── email.token.json │ └── phoneNumber.token.json ├── __test__ ├── CredentialSignerVerifier.test.js ├── SecureRandom.test.js ├── SecureRandomMock.test.js ├── aggregate.test.js ├── claim │ ├── Claim.test.js │ └── UserCollectableAttributesWithMockedDefinitions.js ├── creds │ ├── VerifiableCredential.test.js │ ├── VerifiableCredentialProxy.test.js │ ├── fixtures │ │ ├── Address.json │ │ ├── Cred1.json │ │ ├── CredExpired.json │ │ ├── CredFiltered1.json │ │ ├── CredWithFutureExpiry.json │ │ ├── CredentialAddress.json │ │ ├── CredentialAttestationFaked.json │ │ ├── CredentialEmailInvalid.json │ │ ├── Email.json │ │ ├── GenericDocumentId.json │ │ ├── IdDocumentWithoutNonRequiredClaims.json │ │ ├── IdDocumentWithoutRequiredClaims.json │ │ ├── Identity.json │ │ ├── PermanentAnchor.json │ │ ├── PhoneNumber.json │ │ ├── TempAnchor.json │ │ ├── VCPermanentAnchor.json │ │ ├── VCTempAnchor.json │ │ ├── VCWithTamperedLeafValue.json │ │ ├── emailCredentialOld.json │ │ └── filteredIdDocument-v3.json │ └── proxyFixtures │ │ ├── Address.json │ │ ├── Cred1.json │ │ ├── CredExpired.json │ │ ├── CredFiltered1.json │ │ ├── CredWithFutureExpiry.json │ │ ├── CredentialAddress.json │ │ ├── CredentialAttestationFaked.json │ │ ├── CredentialEmailInvalid.json │ │ ├── Email.json │ │ ├── GenericDocumentId.json │ │ ├── IdDocumentWithoutNonRequiredClaims.json │ │ ├── IdDocumentWithoutRequiredClaims.json │ │ ├── Identity.json │ │ ├── PermanentAnchor.json │ │ ├── PhoneNumber.json │ │ ├── TempAnchor.json │ │ ├── VCPermanentAnchor.json │ │ ├── VCTempAnchor.json │ │ ├── VCWithTamperedLeafValue.json │ │ └── filteredIdDocument-v2.json ├── errors │ └── idvErrors.test.js ├── index.test.js ├── isClaimRelated.test.js ├── isValidGlobalIdentifier.test.js ├── lib │ ├── did.test.js │ ├── fixtures │ │ ├── sol.did.controlled.json │ │ ├── sol.did.controller.json │ │ ├── sol.did.no_default_key.json │ │ └── sol.did.sparse.json │ ├── signerVerifier.test.js │ └── util │ │ └── did.js ├── schema │ └── fixtures │ │ └── credential-test:IdDocument-v1.schema.json ├── schemaLoader.test.js └── services │ ├── AggregationService.test.js │ ├── MiniCryptoManagerImpl.test.js │ ├── config.test.js │ ├── configBranch.test.js │ └── services.test.js ├── audit-ci.json ├── babel.config.js ├── package-lock.json ├── package.json ├── scripts ├── configuration.js ├── description.js └── generateSampleCredential.js └── src ├── AggregationHandler.js ├── SecureRandom.js ├── claim ├── Claim.js ├── __mocks__ │ └── definitions.js └── definitions.js ├── constants ├── headers.js └── index.js ├── creds ├── ClaimModel.js ├── CredentialSignerVerifier.js ├── CvcMerkleProof.js ├── VerifiableCredential.js ├── VerifiableCredentialProxy.js ├── __mocks__ │ └── definitions.js └── definitions.js ├── errors ├── definitions.js ├── idvErrors.js └── index.js ├── index.js ├── isClaimRelated.js ├── isValidGlobalIdentifier.js ├── lib ├── crypto.js ├── did.js ├── signerVerifier.js └── stringUtils.js ├── logger.js ├── schemas └── jsonSchema │ ├── index.js │ └── loaders │ └── cvc.js ├── services ├── DefaultAnchorServiceImpl.js ├── DummyAnchorServiceImpl.js ├── MiniCryptoManagerImpl.js ├── __mocks__ │ └── httpService.js ├── anchorService.js ├── config.js ├── httpService.js └── index.js ├── timeHelper.js └── uca └── UCA.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | defaults: &defaults 4 | working_directory: ~/repo 5 | docker: 6 | - image: circleci/node:12.19.0 7 | 8 | workflows: 9 | version: 2 10 | 11 | build-and-test: 12 | jobs: 13 | - build 14 | 15 | build-tag: 16 | jobs: 17 | - build: 18 | filters: 19 | tags: 20 | only: /^release\..*$/ 21 | branches: 22 | ignore: /.*/ 23 | - release: 24 | context: Production 25 | requires: 26 | - build 27 | filters: 28 | tags: 29 | only: /^release\..*$/ 30 | branches: 31 | ignore: /.*/ 32 | 33 | deploy-npm: 34 | jobs: 35 | - build: 36 | filters: 37 | tags: 38 | only: /^v\d+\.\d+\.\d+.*/ 39 | branches: 40 | ignore: /.*/ 41 | - deploy: 42 | context: Production 43 | requires: 44 | - build 45 | filters: 46 | tags: 47 | only: /^v\d+\.\d+\.\d+.*/ 48 | branches: 49 | ignore: /.*/ 50 | 51 | jobs: 52 | build: 53 | <<: *defaults 54 | steps: 55 | - checkout 56 | - restore_cache: 57 | keys: 58 | - v1-dependencies-{{ checksum "package.json" }}-{{checksum "package-lock.json"}} 59 | - run: sudo npm install -g npm@6.14.13 60 | - run: npm ci 61 | - save_cache: 62 | paths: 63 | - node_modules 64 | key: v1-dependencies-{{ checksum "package.json" }}-{{checksum "package-lock.json"}} 65 | - run: 66 | name: run tests incl coverage 67 | command: npm run test 68 | - run: npm run lint 69 | - run: npm run build 70 | - run: npm run audit-ci -- --pass-enoaudit 71 | - persist_to_workspace: 72 | root: ~/repo 73 | paths: . 74 | 75 | release: 76 | <<: *defaults 77 | environment: 78 | HUB_ARTIFACT_VERSION: 2.7.0 79 | HUB_ARTIFACT: hub-linux-amd64-2.7.0 80 | steps: 81 | - checkout 82 | - restore_cache: 83 | keys: 84 | - v1-dependencies-{{ checksum "package.json" }}-{{checksum "package-lock.json"}} 85 | - run: sudo npm install -g npm@6.14.13 86 | - run: | 87 | sh ./.circleci/install_hub.sh 88 | mkdir -p ~/.config/ && echo -e "github.com:\n- user: civictechuser\n oauth_token: $GITHUB_API_KEY\n protocol: https\n" > ~/.config/hub 89 | - run: npm ci 90 | - save_cache: 91 | paths: 92 | - node_modules 93 | key: v1-dependencies-{{ checksum "package.json" }}-{{checksum "package-lock.json"}} 94 | - run: 95 | name: run tests incl coverage 96 | command: npm run test 97 | - run: npm run lint 98 | - run: npm run build 99 | - run: 100 | name: git config 101 | command: | 102 | git config credential.helper 'cache --timeout=120' 103 | git config user.email "no-reply@civic.com" 104 | git config user.name "CI Deployer" 105 | git config --global push.default simple 106 | - run: 107 | name: create-release 108 | command: npm run release:create 109 | - run: 110 | name: delete-release-tag 111 | command: git push --delete origin $CIRCLE_TAG 112 | - run: | 113 | hub release delete $CIRCLE_TAG 114 | deploy: 115 | <<: *defaults 116 | steps: 117 | - attach_workspace: 118 | at: ~/repo 119 | - run: 120 | name: Authenticate with registry 121 | command: echo "//registry.npmjs.org/:_authToken=$IDENTITY_NPM_TOKEN" > ~/repo/.npmrc 122 | - run: 123 | name: Publish package 124 | command: npm publish --access=public 125 | -------------------------------------------------------------------------------- /.circleci/install_hub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | mkdir -p .hub_tmp 5 | cd .hub_tmp 6 | 7 | if [ ! -f "$HUB_ARTIFACT.tgz" ]; then 8 | wget https://github.com/github/hub/releases/download/v$HUB_ARTIFACT_VERSION/$HUB_ARTIFACT.tgz 9 | fi 10 | 11 | tar -xvzf $HUB_ARTIFACT.tgz 12 | sudo ./$HUB_ARTIFACT/install 13 | 14 | rm -rf ./$HUB_ARTIFACT -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | scripts/ 2 | dist/ 3 | reports/ 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "browser": true, 5 | "commonjs": true, 6 | "es6": true, 7 | "jest": true 8 | }, 9 | "plugins": [ 10 | "no-only-tests" 11 | ], 12 | "rules": { 13 | "max-len": ["warn", 120] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | reports/* 2 | node_modules/ 3 | .idea/ 4 | .vscode/ 5 | *.iml 6 | npm-debug.log 7 | build 8 | .DS_Store 9 | dist/ 10 | .history/ 11 | .tmp/ 12 | .history 13 | 14 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .circleci 2 | reports 3 | node_modules 4 | demo 5 | build 6 | __integrations__ 7 | __test__ 8 | .idea 9 | .tmp 10 | -------------------------------------------------------------------------------- /AUDIT.md: -------------------------------------------------------------------------------- 1 | This project uses [npm audit](https://docs.npmjs.com/cli/audit) to scan dependencies for vulnerabilities 2 | and automatically install any compatible updates to vulnerable dependencies. 3 | The security audit is also integrated into the project's CI pipeline via [audit-ci](https://github.com/IBM/audit-ci) command 4 | which fails the build if there is any vulnerability found. 5 | It is possible to ignore specific errors by whitelisting them in [audit-ci config.](./audit-ci.json). 6 | 7 | ## NPM audit whitelist 8 | Whenever you whitelist a specific advisory it is required to refer it to here and justify the whitelisting. 9 | 10 | ### Advisories 11 | 12 | | # | Level | Module | Title | Explanation | 13 | |------|-------|---------|------|-------------| 14 | | 565 | Moderate | npm>ssri | Regular Expression Denial of Service | dev dependency only | 15 | | 786 | Low | babel-cli > chokidar > anymatch > micromatch > braces | Regular Expression Denial of Service | dev dependency only | 16 | | 1500 | Low | babel-minify>yargs-parser | Prototype Pollution | dev dependency only | 17 | | 1654 | Moderate | npm>libnpx>y18n | Regular Expression Denial of Service | dev dependency only | 18 | | 1677 | Moderate | npm>hosted-git-info | Regular Expression Denial of Service | dev dependency only | 19 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Open Source Code of Conduct 2 | This code of conduct outlines our expectations for participants within the Identity.com Open Source community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community. 3 | 4 | 5 | # Our open source community strives to: 6 | 7 | 8 | * Be friendly and patient. 9 | * Be welcoming: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, color, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. 10 | * Be considerate: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we’re a world-wide community, so you might not be communicating in someone else’s primary language. 11 | * Be respectful: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. 12 | * Be careful in the words that you choose: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren’t acceptable. This includes, but is not limited to: 13 | * Violent threats or language directed against another person. 14 | * Discriminatory jokes and language. 15 | * Posting sexually explicit or violent material. 16 | * Posting (or threatening to post) other people’s personally identifying information (“doxing”). 17 | * Personal insults, especially those using racist or sexist terms. 18 | * Unwelcome sexual attention. 19 | * Advocating for, or encouraging, any of the above behavior. 20 | * Repeated harassment of others. In general, if someone asks you to stop, then stop. 21 | * When we disagree, try to understand why: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. 22 | * Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. 23 | 24 | 25 | This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter. 26 | 27 | 28 | # Diversity Statement 29 | We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong. 30 | 31 | 32 | Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected characteristics above, including participants with disabilities. 33 | 34 | 35 | # Reporting Issues 36 | If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via https://www.identity.com/about/contact-us/. All reports will be handled with discretion. In your report please include: 37 | 38 | * Your contact information. 39 | * Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link. 40 | * Any additional information that may be helpful. 41 | 42 | 43 | After filing a report, a representative will contact you personally. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. A representative will then review the incident, follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality requests for the purpose of protecting victims of abuse. 44 | 45 | 46 | Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our community without warning. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | We’re still working out the kinks to make contributing to this project as easy and transparent as possible, but we’re not quite there yet. Hopefully this document makes the process for contributing clear and answers some questions that you may have. 3 | 4 | # Code of Conduct 5 | Identity.com has adopted a [Code of Conduct](CODE_OF_CONDUCT.md) that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated. 6 | 7 | # Contributors & Team Members Development 8 | Most internal changes made by Civic & Identity.com engineers will be synced to GitHub. Civic & Identity.com use this code in production. The team is likely to have an enterprise version of the code containing specific environment details and that part is not synced with the code here. 9 | Changes from the community are handled through GitHub pull requests which go through our review process. Once a change made on GitHub is approved, it will be imported to the Civic & Identity.com internal repositories. 10 | 11 | # Branch Organization 12 | We will do our best to keep the master branch in good shape, with tests passing at all times. But in order to move fast, we will make API changes that your application might not be compatible with. We recommend that you use the latest stable and published version. 13 | If you send a pull request, please do it against the master branch. We maintain stable branches for major versions separately.We accept pull requests against latest major branch directly if it is a bugfix related to its version. This fix will be also applied to the master branch by the Core team. 14 | 15 | # Semantic Versioning 16 | This software follows semantic versioning. We release patch versions for bug fixes, minor versions for new features, and major versions for any breaking changes. When we make breaking changes, we also introduce deprecation warnings in a minor version so that our users learn about the upcoming changes and migrate their code in advance. 17 | Every significant change is documented in the changelog file. 18 | 19 | # Bugs 20 | ## Where to Find Known Issues 21 | We are using GitHub Issues for our public bugs. Core team will keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new task, try to make sure your problem doesn’t already exist. 22 | ## Reporting New Issues 23 | The best way to get your bug fixed is to provide a reduced test case. 24 | How to Get in Touch 25 | 26 | GitHub Issues: Create a ticket with the specific tag: [question] ; [feature request]; [suggestion] ; [discussion] 27 | Identity.com website contact form 28 | 29 | # Proposing a Change 30 | If you intend to change the public API, or make any non-trivial changes to the implementation, we recommend filing an issue. This lets us reach an agreement on your proposal before you put significant effort into it. 31 | If you’re only fixing a bug, it’s fine to submit a pull request right away but we still recommend to file an issue detailing what you’re fixing. This is helpful in case we don’t accept that specific fix but want to keep track of the issue. 32 | 33 | # Your First Pull Request 34 | Working on your first Pull Request? You can learn how from this free video series: 35 | [How to Contribute](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) to an Open Source Project on GitHub 36 | If you decide to fix an issue, please be sure to check the comment thread in case somebody is already working on a fix. If nobody is working on it at the moment, please leave a comment stating that you intend to work on it so other people don’t accidentally duplicate your effort. 37 | If somebody claims an issue but doesn’t follow up for more than two weeks, it’s fine to take it over but you should still leave a comment. 38 | 39 | # Sending a Pull Request 40 | The Identity.com team is monitoring for pull requests. We will review your pull request and either merge it, request changes to it, or close it with an explanation. 41 | Before submitting a pull request, please make sure the following is done: 42 | Fork the repository and create your branch from master. 43 | Run `npm install` in the repository root. 44 | If you’ve fixed a bug or added code that should be tested, add tests! 45 | Ensure the test suite passes (`npm test`). 46 | Format your code with eslint (`npm run lint`). 47 | If you haven’t already, complete the CLA. 48 | 49 | # Contributor License Agreement (CLA) 50 | By contributing to Identity.com projects, you agree that your contributions will be licensed under its MIT license. 51 | Contribution Prerequisites 52 | 53 | # Prerequisites 54 | Please follow [README](README.md) instructions. 55 | 56 | # Development Workflow 57 | Please follow [README](README.md) instructions. 58 | 59 | # Style Guide 60 | We use an automatic code formatter called ESLint. Run `npm run lint` after making any changes to the code. 61 | Then, our linter will catch most issues that may exist in your code. 62 | However, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at Airbnb’s Style Guide will guide you in the right direction. 63 | 64 | # License 65 | By contributing to Identity.com projects, you agree that your contributions will be licensed under its MIT license. 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Identity.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /__integrations__/credentials/VerifiableCredential.test.js: -------------------------------------------------------------------------------- 1 | const uuidv4 = require('uuid/v4'); 2 | const { Claim } = require('../../src/claim/Claim'); 3 | const VC = require('../../src/creds/VerifiableCredential'); 4 | const { schemaLoader, CVCSchemaLoader } = require('../../src'); 5 | 6 | const credentialSubject = 'did:sol:J2vss1hB3kgEfQMSSdvvjwRm3JdyFWp7S7dbX5mudS4V'; 7 | 8 | jest.setTimeout(200000); 9 | 10 | describe('Integration Tests for Verifiable Credentials', () => { 11 | beforeAll(() => { 12 | schemaLoader.addLoader(new CVCSchemaLoader()); 13 | }); 14 | 15 | beforeEach(() => { 16 | schemaLoader.reset(); 17 | }); 18 | 19 | it('should request an anchor for Credential and return an temporary attestation', async (done) => { 20 | const name = await Claim.create('claim-cvc:Identity.name-v1', 21 | { givenNames: 'Joao', otherNames: 'Barbosa', familyNames: 'Santos' }); 22 | 23 | const dob = await Claim.create('claim-cvc:Identity.dateOfBirth-v1', { day: 20, month: 3, year: 1978 }); 24 | const cred = await VC.create('credential-cvc:Identity-v3', uuidv4(), null, credentialSubject, [name, dob]); 25 | return cred.requestAnchor().then((updated) => { 26 | expect(updated.proof.anchor.type).toBe('temporary'); 27 | expect(updated.proof.anchor.value).not.toBeDefined(); 28 | expect(updated.proof.anchor).toBeDefined(); 29 | expect(updated.proof.anchor.schema).toBe('dummy-20180201'); 30 | done(); 31 | }); 32 | }); 33 | 34 | it('should refresh an temporary anchoring with an permanent one', async (done) => { 35 | const name = await Claim.create('claim-cvc:Identity.name-v1', 36 | { givenNames: 'Joao', otherNames: 'Barbosa', familyNames: 'Santos' }); 37 | 38 | const dob = await Claim.create('claim-cvc:Identity.dateOfBirth-v1', { day: 20, month: 3, year: 1978 }); 39 | const cred = await VC.create('credential-cvc:Identity-v3', uuidv4(), null, credentialSubject, [name, dob]); 40 | return cred.requestAnchor().then((updated) => { 41 | expect(updated.proof.anchor).toBeDefined(); 42 | return updated.updateAnchor().then((newUpdated) => { 43 | expect(newUpdated.proof.anchor.type).toBe('permanent'); 44 | expect(newUpdated.proof.anchor).toBeDefined(); 45 | expect(newUpdated.proof.anchor.value).toBeDefined(); 46 | done(); 47 | }); 48 | }); 49 | }); 50 | it('should revoke the permanent anchor and succed verification', async (done) => { 51 | const name = await Claim.create('claim-cvc:Identity.name-v1', 52 | { givenNames: 'Joao', otherNames: 'Barbosa', familyNames: 'Santos' }); 53 | 54 | const dob = await Claim.create('claim-cvc:Identity.dateOfBirth-v1', { day: 20, month: 3, year: 1978 }); 55 | const cred = await VC.create('credential-cvc:Identity-v3', uuidv4(), null, credentialSubject, [name, dob]); 56 | await cred.requestAnchor(); 57 | await cred.updateAnchor(); 58 | const validation = await cred.verifyAttestation(); 59 | if (validation) { 60 | const isRevoked = await cred.revokeAttestation(); 61 | expect(isRevoked).toBeTruthy(); 62 | } 63 | done(); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Credential/Address.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": null, 3 | "issuer": "did:ethr:0x1ddcbae835c47c8d9159756c167994931a5f01e8", 4 | "issuanceDate": "2018-09-21T12:39:38.605Z", 5 | "identifier": "civ:Credential:Address", 6 | "expirationDate": "+132017-07-06T20:39:38.606Z", 7 | "version": "1", 8 | "type": [ 9 | "Credential", 10 | "civ:Credential:Address" 11 | ], 12 | "claim": { 13 | "type": { 14 | "address": { 15 | "city": "Belo Horizonte", 16 | "country": "Brazil", 17 | "county": "Sao Bento", 18 | "state": "Minas Gerais", 19 | "street": "Alameda dos Anjos", 20 | "unit": "", 21 | "zipCode": "94103345" 22 | } 23 | } 24 | }, 25 | "proof": { 26 | "type": "CivicMerkleProof2018", 27 | "merkleRoot": "39bdc215fd65469fdedbfe9de26d9f8506e7b6e9bac169122c96232e4384a9ba", 28 | "anchor": { 29 | "subject": { 30 | "pub": "xpub:dummy", 31 | "label": "civ:Credential:Address", 32 | "data": "39bdc215fd65469fdedbfe9de26d9f8506e7b6e9bac169122c96232e4384a9ba", 33 | "signature": "3044022051050e0ae245cf6603780b7e9f637a48a3044980b1eb185b372525fe00914ea402204e6a9e9843a82a9f40385293a89dc50deae7b450339a5edaaf192307f9ee3670" 34 | }, 35 | "walletId": "5ba4e69078fe66bf03596d3069aac58a", 36 | "cosigners": [ 37 | { 38 | "pub": "xpub:dummy" 39 | }, 40 | { 41 | "pub": "xpub:dummy" 42 | } 43 | ], 44 | "authority": { 45 | "pub": "xpub:dummy", 46 | "path": "/" 47 | }, 48 | "coin": "dummycoin", 49 | "tx": "fdfd000047304402200604457b0ad8128141eced5fe77c5f9fa6e3f38aef532730200000001a86f9972048bbde6ce2aa5af60a5d62181012816aa750e951fae46fa4dfeedc9444cd4b8d190b1eda000000000220134eb8e9aea315a247b70292048e2fb2ea140d070dab12915622810b1abc804e41483045022100fe9893bae41c050553e76ed376f19d9765e34b5c1354d03547511285cf0798010220433a83ee31e7a92b21d434a2b974721c24f15b46865a8cc33af89163004b965f414c6952210352f39b6fe03ff3c284ce08eb56260a75944da0a014e7576c851bd37769a65fb0210213ca75ff709ede0bb39e35c3460e92b4d6732034dac0495006d3245488a65e492102c5a6eb9db7e62912587ed74440a461895b2b687d043de1ec5cdf3c714d6a981553aeffffffff02111b63010000000017a914a8262cc37cd8394c9820bc34a47070d14ea3b1cd87fb1700000000000017a914a5687e1d35e460730c111327b35e5187b98c936d8700000000", 50 | "network": "dummynet", 51 | "value": 23279096, 52 | "type": "permanent", 53 | "civicAsPrimary": false, 54 | "schema": "dummy-20180201" 55 | }, 56 | "leaves": [ 57 | { 58 | "identifier": "civ:Type:address", 59 | "value": "urn:city:c61e2fbaa84f111f5015ea5d13d177b3d5b7b8b6f279995910426d87b6fd3364:Belo Horizonte|urn:country:2ac8c1e90dbf08266deb7c498e29f61fc33d7a37029aafb7c5eaa5b1a33080c2:Brazil|urn:county:8c46808c83ed11972e2d52a6ae606528e6e63f3e52f5e73ea7ad803dba68ce53:Sao Bento|urn:state:00c854bd27916c1453bfdf9d02e0c3eb80fc292fa641292082097e3065154629:Minas Gerais|urn:street:baff9c1cad7241630c94f43c1a18a0529c5427e39b1e7117366e46766b24c6cd:Alameda dos Anjos|urn:unit:6a560391ae9ee0d33c0372fd56341aa5f910244aec1aefa8468e14b3a191e5e2:|urn:zipCode:f6ba4567aeae9e62461d9749efbb08d911b2f8da224404eefcaebdb84d34978e:94103345|", 60 | "claimPath": "type.address", 61 | "targetHash": "c79fc682b284c6a0c68fdb0e9a6865d268ce19b07208244479e1a8669c51afea", 62 | "node": [ 63 | { 64 | "right": "a4ab2e813ed683a683cdefbc7c629ac10fff00cf754bef93f310d8ba02ae48d1" 65 | }, 66 | { 67 | "right": "f404eb6c309915b62fc0c90117b173a245db45e2a54bc8a2fea4bafc97d8e227" 68 | }, 69 | { 70 | "right": "203855cbc830f0b96b63b1ccc821366ad36d801594cd3724a6f6c55e1afee28a" 71 | }, 72 | { 73 | "right": "11b9de05c354fbd98ccfb11a2eadc286d1a239cde4bcb6785da7c6eade927bde" 74 | } 75 | ] 76 | }, 77 | { 78 | "identifier": "civ:Meta:issuer", 79 | "value": "urn:issuer:93bc6f122f2b48e6875bff331235d6607461712e709084d1e9b3d0c47af190ee:did:ethr:0x1ddcbae835c47c8d9159756c167994931a5f01e8", 80 | "claimPath": "meta.issuer", 81 | "targetHash": "a4ab2e813ed683a683cdefbc7c629ac10fff00cf754bef93f310d8ba02ae48d1", 82 | "node": [ 83 | { 84 | "left": "c79fc682b284c6a0c68fdb0e9a6865d268ce19b07208244479e1a8669c51afea" 85 | }, 86 | { 87 | "right": "f404eb6c309915b62fc0c90117b173a245db45e2a54bc8a2fea4bafc97d8e227" 88 | }, 89 | { 90 | "right": "203855cbc830f0b96b63b1ccc821366ad36d801594cd3724a6f6c55e1afee28a" 91 | }, 92 | { 93 | "right": "11b9de05c354fbd98ccfb11a2eadc286d1a239cde4bcb6785da7c6eade927bde" 94 | } 95 | ] 96 | }, 97 | { 98 | "identifier": "civ:Meta:issuanceDate", 99 | "value": "urn:issuanceDate:af3043d6625a15751a059e3d35a830f69512f7b61191f6eac28f1534ce440a54:2018-09-21T12:39:38.605Z", 100 | "claimPath": "meta.issuanceDate", 101 | "targetHash": "38970729a5415d1439720e0db6312335a570291ac63775881b0abf6277836f9d", 102 | "node": [ 103 | { 104 | "right": "af35fa98f6f196de377991d8980cb8b0eae3e97d8c9fa148b0c7249cea05b921" 105 | }, 106 | { 107 | "left": "9984f0dea11aeeff0e4c37e638378301d3bc017a37c90ecc2c603486f5043945" 108 | }, 109 | { 110 | "right": "203855cbc830f0b96b63b1ccc821366ad36d801594cd3724a6f6c55e1afee28a" 111 | }, 112 | { 113 | "right": "11b9de05c354fbd98ccfb11a2eadc286d1a239cde4bcb6785da7c6eade927bde" 114 | } 115 | ] 116 | }, 117 | { 118 | "identifier": "civ:Meta:expirationDate", 119 | "value": "urn:expirationDate:82f1890a3942ba4bd7deafa54929b76974a2bc31095874d489f0185c4422cb12:+132017-07-06T20:39:38.606Z", 120 | "claimPath": "meta.expirationDate", 121 | "targetHash": "af35fa98f6f196de377991d8980cb8b0eae3e97d8c9fa148b0c7249cea05b921", 122 | "node": [ 123 | { 124 | "left": "38970729a5415d1439720e0db6312335a570291ac63775881b0abf6277836f9d" 125 | }, 126 | { 127 | "left": "9984f0dea11aeeff0e4c37e638378301d3bc017a37c90ecc2c603486f5043945" 128 | }, 129 | { 130 | "right": "203855cbc830f0b96b63b1ccc821366ad36d801594cd3724a6f6c55e1afee28a" 131 | }, 132 | { 133 | "right": "11b9de05c354fbd98ccfb11a2eadc286d1a239cde4bcb6785da7c6eade927bde" 134 | } 135 | ] 136 | } 137 | ] 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Credential/CivicBasic.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": null, 3 | "issuer": "did:ethr:0x1ddcbae835c47c8d9159756c167994931a5f01e8", 4 | "issuanceDate": "2018-09-21T12:39:37.423Z", 5 | "identifier": "civ:Credential:CivicBasic", 6 | "expirationDate": "+132017-07-06T20:39:37.423Z", 7 | "version": "1", 8 | "type": [ 9 | "Credential", 10 | "civ:Credential:CivicBasic" 11 | ], 12 | "claim": { 13 | "type": { 14 | "email": { 15 | "domain": "civic.com", 16 | "user": "savio" 17 | }, 18 | "phone": { 19 | "countryCode": "55", 20 | "number": "31999998888" 21 | } 22 | } 23 | }, 24 | "proof": { 25 | "type": "CivicMerkleProof2018", 26 | "merkleRoot": "933595ae71f5e898611342a03c877db9c1be98eb95496007ec415484c9e6c1eb", 27 | "anchor": { 28 | "subject": { 29 | "pub": "xpub:dummy", 30 | "label": "civ:Credential:CivicBasic", 31 | "data": "933595ae71f5e898611342a03c877db9c1be98eb95496007ec415484c9e6c1eb", 32 | "signature": "3045022100e3c70c0d04adf5c078caac6d89adebf6f71650c4cde9c5483d39c23aa418d49e02204f10bc39f8ec758dad194b60b674815836d173297a7fae7261a0b80749c5748d" 33 | }, 34 | "walletId": "5ba4e6900e0ebfae03a40edfb1a79eef", 35 | "cosigners": [ 36 | { 37 | "pub": "xpub:dummy" 38 | }, 39 | { 40 | "pub": "xpub:dummy" 41 | } 42 | ], 43 | "authority": { 44 | "pub": "xpub:dummy", 45 | "path": "/" 46 | }, 47 | "coin": "dummycoin", 48 | "tx": "cb1f03a2701000000fdfd00004730440220502373558960df8e7975e97e864ecf854020000000102e476ddbbe80a509e3bbc5230c123204e014985c33cbe89f9b17340cb53a96145404920016b80d848531a02206c0316fbcdd03d2b1199ee0bd3e0e6aeef42ab146de76bf076a30d9acf2f0b66414830450221008980cfbf25064e536a7989b289e75739371ec52df8e41e1b093edfda04b59e53022041b98f227c24971c64f633bc7a20cf0d3f935e6af3c62522eb6463ee5684f391414c69522103385dd2a8fc56f9ccdc329f383648e31ff89594fb8ae5b914c85e7c7879de7b2e21021bb2cc663545824cfde13299f494c6eeb77a43b38a07eedb4d6d6bcce78774d4210286fcfaa273f4a965471b20afe542097a46ae97e0a518006ecca64e70f4a4aa6b53aeffffffff02fb1700000000000017a9148d4a386269b21a79bd986208ceb6eaf8f603e48f87664663010000000017a914ea71cc1a5c56fca93559d0114f4c0c57e284881f8700000000", 49 | "network": "dummynet", 50 | "value": 23290189, 51 | "type": "permanent", 52 | "civicAsPrimary": false, 53 | "schema": "dummy-20180201" 54 | }, 55 | "leaves": [ 56 | { 57 | "identifier": "civ:Meta:issuer", 58 | "value": "urn:issuer:ff1da703a56869899acd988bbb59c5d435e46e212d7e73db8c373527c41c90de:did:ethr:0x1ddcbae835c47c8d9159756c167994931a5f01e8", 59 | "claimPath": "meta.issuer", 60 | "targetHash": "64be97448cffc83cf5a53e2ff7d9f922eb44b778f12a3fe6555ab58250258811", 61 | "node": [ 62 | { 63 | "right": "9352227473e984b650d8d8168736069ff466e480aeb1096e1a97f5dfd968de1a" 64 | }, 65 | { 66 | "right": "c3d5c87a0d028f709147657d680fe3ce6e509bfcc842f87a84f48beee096e5f3" 67 | }, 68 | { 69 | "right": "01a2a9f4a5817d7935572e0b16f18b3ac3d8d8601e7ea631df8f0aa9d2c4723e" 70 | }, 71 | { 72 | "right": "d0bb26cc698d36456c59b8da9851655d34ea951cf7cb583f4ebff82159584fad" 73 | } 74 | ] 75 | }, 76 | { 77 | "identifier": "civ:Meta:issuanceDate", 78 | "value": "urn:issuanceDate:e7637f9f715fe4e416297371bdf72139441d879f4945af5deac0a8e4b36ad13d:2018-09-21T12:39:37.423Z", 79 | "claimPath": "meta.issuanceDate", 80 | "targetHash": "9352227473e984b650d8d8168736069ff466e480aeb1096e1a97f5dfd968de1a", 81 | "node": [ 82 | { 83 | "left": "64be97448cffc83cf5a53e2ff7d9f922eb44b778f12a3fe6555ab58250258811" 84 | }, 85 | { 86 | "right": "c3d5c87a0d028f709147657d680fe3ce6e509bfcc842f87a84f48beee096e5f3" 87 | }, 88 | { 89 | "right": "01a2a9f4a5817d7935572e0b16f18b3ac3d8d8601e7ea631df8f0aa9d2c4723e" 90 | }, 91 | { 92 | "right": "d0bb26cc698d36456c59b8da9851655d34ea951cf7cb583f4ebff82159584fad" 93 | } 94 | ] 95 | }, 96 | { 97 | "identifier": "civ:Meta:expirationDate", 98 | "value": "urn:expirationDate:f94a12a99aed0fae1bc7397b7087f3a0a31c273d4a1d9f3ad3fabf090ce8ab02:+132017-07-06T20:39:37.423Z", 99 | "claimPath": "meta.expirationDate", 100 | "targetHash": "c6000fcf20b4c0e533efeb1a0f8b3e483d8d2ff923f4e5d940ec75cbb6fcb5cf", 101 | "node": [ 102 | { 103 | "right": "a9abca37cd8fa2ab6305e4db5d5b5681e783f8cf79b5c068417fcece544174bf" 104 | }, 105 | { 106 | "left": "5e82a2597bb35693f4f968b6e0ef8299286e6027b532a85e8eb3da0bde32d598" 107 | }, 108 | { 109 | "right": "01a2a9f4a5817d7935572e0b16f18b3ac3d8d8601e7ea631df8f0aa9d2c4723e" 110 | }, 111 | { 112 | "right": "d0bb26cc698d36456c59b8da9851655d34ea951cf7cb583f4ebff82159584fad" 113 | } 114 | ] 115 | } 116 | ] 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/dateOfBirth.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 6.521646969800926, 3 | "month": 6.236838282537503, 4 | "year": 1928.7565303507129 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/dateOfExpiry.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 0.5249914172066497, 3 | "month": 9.769871658075989, 4 | "year": 1981.3611959096331 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/dateOfIssue.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 10.228468018628824, 3 | "month": 12.544796158568127, 4 | "year": 1901.0330199220975 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/firstName.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstName": "m4HQrHJBMy" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/givenName.json: -------------------------------------------------------------------------------- 1 | { 2 | "givenName": "Qf6saHd1Zy" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/name.first.json: -------------------------------------------------------------------------------- 1 | { 2 | "first": "d2JWs3Erdi" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/name.json: -------------------------------------------------------------------------------- 1 | { 2 | "first": "nXyn3KLpuN", 3 | "middle": "S2QnBbYREf", 4 | "last": "Yag7TzMxmy", 5 | "nickname": "DjDHzrNjfh" 6 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/name.last.json: -------------------------------------------------------------------------------- 1 | { 2 | "last": "q0r43N6XAr" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/name.middle.json: -------------------------------------------------------------------------------- 1 | { 2 | "middle": "LXNFDLuzw6" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/name.nickname.json: -------------------------------------------------------------------------------- 1 | { 2 | "nickname": "vxN1DZVCy8" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Identity/name.username.json: -------------------------------------------------------------------------------- 1 | { 2 | "username": "D1qmiRwwpl" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Meta/expirationDate.json: -------------------------------------------------------------------------------- 1 | { 2 | "expirationDate": "gSOTgTRRUy" 3 | } 4 | -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Meta/issuanceDate.json: -------------------------------------------------------------------------------- 1 | { 2 | "issuanceDate": "bykfLSTQm1" 3 | } 4 | -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Meta/issuer.json: -------------------------------------------------------------------------------- 1 | { 2 | "issuer": "AbUFEjsrwr" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Random/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": "NkXu1PbBGw" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.city.json: -------------------------------------------------------------------------------- 1 | { 2 | "city": "bH7Z0J8cjm" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.country.json: -------------------------------------------------------------------------------- 1 | { 2 | "country": "ZSBM8k51si" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.county.json: -------------------------------------------------------------------------------- 1 | { 2 | "county": "CJ5Wkf87dm" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.json: -------------------------------------------------------------------------------- 1 | { 2 | "street": "FnEjs4mRmz", 3 | "unit": "7bwIUsixzn", 4 | "city": "WKui0bMTIN", 5 | "zipCode": "B5Uyc7bbOt", 6 | "state": "ST2LrahCPO", 7 | "county": "cnZTMsdZgQ", 8 | "country": "tAKNZFwqBV" 9 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.state.json: -------------------------------------------------------------------------------- 1 | { 2 | "state": "DLuUp5uiLr" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.street.json: -------------------------------------------------------------------------------- 1 | { 2 | "street": "8GPJVF7A5Y" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.unit.json: -------------------------------------------------------------------------------- 1 | { 2 | "unit": "cp6Abfw3is" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/address.zipCode.json: -------------------------------------------------------------------------------- 1 | { 2 | "zipCode": "uon0Lq8fNF" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/date.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 16.887190847842405, 3 | "month": 4.33208397343556, 4 | "year": 1910.8122881975623 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/day.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 42.60887321150133 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/documentNumber.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentNumber": 4531543134 3 | } 4 | -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/documentType.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentType": "lWMcUrg3NB" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/email.domain.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "R71eM7105z" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/email.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "fpy47GxXdF", 3 | "domain": "IhsNoyWzhn" 4 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/email.user.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "EZjvygRuvb" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/image.image.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "gJtAx17ngp" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/image.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "Qw7qezoa2y", 3 | "md5": "zjSRherUuA" 4 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/image.md5.json: -------------------------------------------------------------------------------- 1 | { 2 | "md5": "XBtUi3kcah" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/month.json: -------------------------------------------------------------------------------- 1 | { 2 | "month": 25.440331784890937 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/phone.countryCode.json: -------------------------------------------------------------------------------- 1 | { 2 | "countryCode": "zdIjOzp2fb" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/phone.json: -------------------------------------------------------------------------------- 1 | { 2 | "number": "YOPqLuSrIf", 3 | "countryCode": "OglxhaFT63" 4 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/phone.number.json: -------------------------------------------------------------------------------- 1 | { 2 | "number": "hbs6bZ8X36" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/shortToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "shortToken": "/01299/" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Type/year.json: -------------------------------------------------------------------------------- 1 | { 2 | "year": 34.51072551849506 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Verify/email.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "dN7kq9Qb72" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/correct/Verify/phoneNumber.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "BhyNbj48ON" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Credential/Address.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": null, 3 | "issuer": "jest:test", 4 | "issued": "2018-07-11T01:54:48.421Z", 5 | "identifier": "civ:Credential:Address", 6 | "expiry": null, 7 | "version": 1, 8 | "type": [ 9 | "Credential", 10 | "civ:Credential:Address" 11 | ], 12 | "claims": { 13 | "type": { 14 | "address": { 15 | "city": "G2doTjSpns", 16 | "country": "W6PdCXudMW", 17 | "county": "HBo3JdLC7s", 18 | "state": "fLKVsEeqDn", 19 | "street": "VaEWBhiGoc", 20 | "unit": "XJw3G31s1y", 21 | "zipCode": "UqpsaKjUcF" 22 | } 23 | } 24 | }, 25 | "signature": { 26 | "type": "CivicMerkleProof2018", 27 | "anchor": { 28 | "subject": { 29 | "pub": "xpub:dummy", 30 | "label": "civ:Credential:Address", 31 | "data": "f8e1b073e1a30a5bd371a55facfc1c8422fe03e8658c0c5dfb48dfd45a2aff93", 32 | "signature": "3045022100d03ab81a9763acff1cc21211a0ae3cce92c55a511beca0974e4b912d51c157a1022017d95b499918832786250a5b7afcf1cd5b592b81b5447409190e77ebe4ac151c" 33 | }, 34 | "walletId": "5b4563887f3245a103c8d40968817c71", 35 | "cosigners": [ 36 | { 37 | "pub": "xpub:dummy" 38 | }, 39 | { 40 | "pub": "xpub:dummy" 41 | } 42 | ], 43 | "authority": { 44 | "pub": "xpub:dummy", 45 | "path": "/" 46 | }, 47 | "coin": "dummycoin", 48 | "tx": "4402204197ec90a3b8c097ba956695bcc6bd8d7d8e0d99ab3f1989d470dc781bc9e77902205e2775a44cba937020000000159d2c2ae40075b290c06f199b373993069cb652f1621efcd608ee784a157894601000000fc004730593f8100692e5138cd802bf7a85cfd491597cc1be82b55615414730440220014dcb22add2a832438cf24fb6624a92e83b077368f912e0b4ca8323bc89939a0220055a1ba5b8176eb007cd1b608cdd897ebb72f82b7011377977ca339cd712c48b414c69522103582c6b40cd15817fb8406cd9d044c359694d28cb6c1994a161c078251614ff8821036948462e4632edd68d972d96117822324ebc34ad71e00384aef7ffcfd0317a7c2102efca14ec339e3b4e5fbeb8706aecf88512631bdedcb4eabfefc5a560fc547cb053aeffffffff02801869010000000017a9142b453a9cde79b4da2f8e85ff3665c4d80ce4cc0f87fb1700000000000017a914e58d4bf1d62ce81adb3772770f891e920605ec908700000000", 49 | "network": "dummynet", 50 | "value": "23671655", 51 | "type": "permanent", 52 | "civicAsPrimary": false, 53 | "schema": "dummy-20180201" 54 | }, 55 | "leavases": [ 56 | { 57 | "identifier": "civ:Type:address", 58 | "value": "urn:city:3f140538fb85280304b2ad90df1e86958cb609deba95d44e5145d61c620b34d6:G2doTjSpns|urn:country:e507c6c6b537992c40f75adb1576a32abb91014a48f9e799bc327a6c7c2e618f:W6PdCXudMW|urn:county:ebb1b91d1e5cb94ffe04361b549a3ffa08a2829fa9fdea590e278d092b8902ad:HBo3JdLC7s|urn:state:37b2a401b64601af2b693ed79ecb47097d87725fa821c2e8f7cc8c7e064cda1e:fLKVsEeqDn|urn:street:74c6033738adc918759b949e2c2c5a26ce1e713cc5b61cf4c1de527d141fadca:VaEWBhiGoc|urn:unit:1e73df52e0a0bd9ee4acbc85845d747a97ae3e857d341cf7aff1d91c9305a56f:XJw3G31s1y|urn:zipCode:78bc1dc1cdd6d5444b7c02504a20ee2d2da7531dde693faeada6f9a4a138c46a:UqpsaKjUcF|", 59 | "claimPath": "type.address", 60 | "targetHash": "2f2bcf1fcd83f537472131a211a49b01f85e89be53ccf9533237c8229d3c86eb", 61 | "proof": [ 62 | { 63 | "right": "ac146c9eb47560eb14846bee704eb95492cee6744af41573fc198e619f5129ed" 64 | }, 65 | { 66 | "right": "74f8f1cd618f95d102ccaddb22536ba23181986b61c3617203a74b3fc3a6bbdc" 67 | }, 68 | { 69 | "right": "296eae55860c2b30f7134cb959f061bf6ffa3ef2bf8f043b5848a1ec841febae" 70 | }, 71 | { 72 | "right": "be92bb41ac2695a11a12677c2eb1f3b79147578b6d93cb8ccb4c625fc3d82666" 73 | } 74 | ] 75 | }, 76 | { 77 | "identifier": "civ:Meta:issuer", 78 | "value": "urn:issuer:134c74d63d2f444f55e7f672d253d9c415dd611972c565a7cb41847d4d173c4e:jest:test", 79 | "claimPath": "meta.issuer", 80 | "targetHash": "ac146c9eb47560eb14846bee704eb95492cee6744af41573fc198e619f5129ed", 81 | "proof": [ 82 | { 83 | "left": "2f2bcf1fcd83f537472131a211a49b01f85e89be53ccf9533237c8229d3c86eb" 84 | }, 85 | { 86 | "right": "74f8f1cd618f95d102ccaddb22536ba23181986b61c3617203a74b3fc3a6bbdc" 87 | }, 88 | { 89 | "right": "296eae55860c2b30f7134cb959f061bf6ffa3ef2bf8f043b5848a1ec841febae" 90 | }, 91 | { 92 | "right": "be92bb41ac2695a11a12677c2eb1f3b79147578b6d93cb8ccb4c625fc3d82666" 93 | } 94 | ] 95 | }, 96 | { 97 | "identifier": "civ:Meta:issued", 98 | "value": "urn:issued:5d8af50d79683a3f0ebaf3015f08b68b2afdb3ed03350fdedf48f32abcdb2de0:2018-07-11T01:54:48.421Z", 99 | "claimPath": "meta.issued", 100 | "targetHash": "94d952068822369eb8542bd4c0750993187b944687202a61b0a64860ccfb3427", 101 | "proof": [ 102 | { 103 | "right": "cb9b2ff87535d047a59639b999f7fd10f6221ed2d789acb0cd904d13663b16bd" 104 | }, 105 | { 106 | "left": "16bb2a17ec869659a1c41f1a1f52b16a4967786f3b0904bf23d462e044cb5d18" 107 | }, 108 | { 109 | "right": "296eae55860c2b30f7134cb959f061bf6ffa3ef2bf8f043b5848a1ec841febae" 110 | }, 111 | { 112 | "right": "be92bb41ac2695a11a12677c2eb1f3b79147578b6d93cb8ccb4c625fc3d82666" 113 | } 114 | ] 115 | }, 116 | { 117 | "identifier": "civ:Meta:expiry", 118 | "value": "urn:expiry:77479ff7baed7e814da32001903eb14dbbd6f20e5a89fde4c5c3ff6221314c01:null", 119 | "claimPath": "meta.expiry", 120 | "targetHash": "cb9b2ff87535d047a59639b999f7fd10f6221ed2d789acb0cd904d13663b16bd", 121 | "proof": [ 122 | { 123 | "left": "94d952068822369eb8542bd4c0750993187b944687202a61b0a64860ccfb3427" 124 | }, 125 | { 126 | "left": "16bb2a17ec869659a1c41f1a1f52b16a4967786f3b0904bf23d462e044cb5d18" 127 | }, 128 | { 129 | "right": "296eae55860c2b30f7134cb959f061bf6ffa3ef2bf8f043b5848a1ec841febae" 130 | }, 131 | { 132 | "right": "be92bb41ac2695a11a12677c2eb1f3b79147578b6d93cb8ccb4c625fc3d82666" 133 | } 134 | ] 135 | } 136 | ] 137 | } 138 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Credential/CivicBasic.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": null, 3 | "issuer": "jest:test", 4 | "issued": "2018-07-11T01:54:37.622Z", 5 | "identifier": "civ:Credential:CivicBasic", 6 | "expiry": null, 7 | "version": 1, 8 | "type": [ 9 | "Credential", 10 | "civ:Credential:CivicBasic" 11 | ], 12 | "signature": { 13 | "type": "CivicMerkleProof2018", 14 | "merkleRoot": "b020f35a6e5a898775761e935bba0420a657773bde95610feb97e0ae93156355", 15 | "anchor": { 16 | "subject": { 17 | "pub": "xpub:dummy", 18 | "label": "civ:Credential:CivicBasic", 19 | "data": "b020f35a6e5a898775761e935bba0420a657773bde95610feb97e0ae93156355", 20 | "signature": "3045022100b3889e8d02eea0a32dc099f6ece2df807427ff8c00f9a6daec96dd6d8ef2779d022061c3abec6a66c3ade93078ccb3b058eba36778b79a20224288bb8667e9d72ffd" 21 | }, 22 | "walletId": "5b45638c883111a903dd3de5dc07a230", 23 | "cosigners": [ 24 | { 25 | "pub": "xpub:dummy" 26 | }, 27 | { 28 | "pub": "xpub:dummy" 29 | } 30 | ], 31 | "authority": { 32 | "pub": "xpub:dummy", 33 | "path": "/" 34 | }, 35 | "coin": "dummycoin", 36 | "tx": "0fdfe0000483045022100f198fe3a0b92672bbf58b16e177158c3a97617d097124a1fd3b15bbc38b8d0f402201da253aa0200000001cd8ac0675d7612ff501222f0dadfabe46cedb054fc83e379eac6b1b4e0917c1c010000057c517fd83f047b18feab7e2abb7d242389c7da2e13162301315370841483045022100a42c9de28d2c53c98abc7ae8b9d5841d3896d05d856eadd102ce9e5004de76980220718f78635d0474728eb7514b361269c1514864f39017ab693886cad5a85a4032414c69522102cf8caabe036a9a4cf78ddb1e67d695073a040f4ff7345c16118003e8b6ea65fd2102a457d78595a3e6b77e2118e7d75d1c5d2390798a489fbbbd8c36a9e3fcece7be2103ffc8cbda695931af830da8ac47f24bb78e9a61029433821156c8a830a3919e1d53aeffffffff02fb1700000000000017a9140207925bd98086db621dc016ad3bfcc20551382c87c77d79010000000017a914b8b4abc62f17c5e544dff7341c7cd78f27be787d8700000000", 37 | "network": "dummynet", 38 | "value": 24746158, 39 | "type": "permanent", 40 | "civicAsPrimary": "true", 41 | "schema": "dummy-20180201" 42 | }, 43 | "leaves": [ 44 | { 45 | "identifier": 25425345, 46 | "value": "urn:issuer:7959fc27b8c71b7670ae2e1e645d1ebf0dd2d7cf6e06230799b1ed57e4920187:jest:test", 47 | "claimPath": "meta.issuer", 48 | "targetHash": "53fc15f51004fa879aed8361c5129a8a95ff4951ffe7420fd6f604932a195167", 49 | "proof": [ 50 | { 51 | "right": "9667eadea6f0c5f1d51cf66e63a562e6dd99a76157e25df7170bc719b1e56398" 52 | }, 53 | { 54 | "right": "47daf1c569b4f24c11e114a0a666d698ecbf72e7a9570c070dc029cb1db95cb1" 55 | }, 56 | { 57 | "right": "1d2356ae2451000b412b58ae5e7f857ae5160933efad1829bf049cba72f6aaab" 58 | }, 59 | { 60 | "right": "187d875e6c15275642e2767b3ef2106750ca32baea02b2916902c1df538e8ba2" 61 | } 62 | ] 63 | }, 64 | { 65 | "identifier": "civ:Meta:issued", 66 | "value": "urn:issued:0d96b6e90eb47ff028eef002346babb30208ebb0bcb9a6e9cf53189892535d98:2018-07-11T01:54:37.622Z", 67 | "claimPath": "meta.issued", 68 | "targetHash": "9667eadea6f0c5f1d51cf66e63a562e6dd99a76157e25df7170bc719b1e56398", 69 | "proof": [ 70 | { 71 | "left": "53fc15f51004fa879aed8361c5129a8a95ff4951ffe7420fd6f604932a195167" 72 | }, 73 | { 74 | "right": "47daf1c569b4f24c11e114a0a666d698ecbf72e7a9570c070dc029cb1db95cb1" 75 | }, 76 | { 77 | "right": "1d2356ae2451000b412b58ae5e7f857ae5160933efad1829bf049cba72f6aaab" 78 | }, 79 | { 80 | "right": "187d875e6c15275642e2767b3ef2106750ca32baea02b2916902c1df538e8ba2" 81 | } 82 | ] 83 | }, 84 | { 85 | "identifier": "civ:Meta:expiry", 86 | "value": "urn:expiry:3d0319ff6040abf674192bee3d873afee49067df9e4e69fbade038a5157e0cdf:null", 87 | "claimPath": "meta.expiry", 88 | "targetHash": "c0c760b1cb7cea24d83fe83f81b6842fa843e928d1b0bd4e35a0260a98f202d1", 89 | "proof": [ 90 | { 91 | "right": "15140cde7c1894d7ae88a6f3dc438a68f93f122dc1d71347087476de4d998e9f" 92 | }, 93 | { 94 | "left": "f2a2024bb45f8c585ad38888f1c1dbcf7d26dd8ba0f21681180a6bbc79231ec6" 95 | }, 96 | { 97 | "right": "1d2356ae2451000b412b58ae5e7f857ae5160933efad1829bf049cba72f6aaab" 98 | }, 99 | { 100 | "right": "187d875e6c15275642e2767b3ef2106750ca32baea02b2916902c1df538e8ba2" 101 | } 102 | ] 103 | } 104 | ] 105 | } 106 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/dateOfBirth.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 6.521646969800926, 3 | "month": 6.236838282537503, 4 | "year": "1928.7565303507129" 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/dateOfExpiry.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 0.5249914172066497, 3 | "month": 9.769871658075989, 4 | "year": "1981.3611959096331" 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/dateOfIssue.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": 10.228468018628824, 3 | "month": 12.544796158568127, 4 | "year": "1901.0330199220975" 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/firstName.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstName": 1451435 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/givenName.json: -------------------------------------------------------------------------------- 1 | { 2 | "givenName": true 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/name.first.json: -------------------------------------------------------------------------------- 1 | { 2 | "first": 345245 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/name.json: -------------------------------------------------------------------------------- 1 | { 2 | "first": 4513452, 3 | "middle": 562156, 4 | "last": 46512453, 5 | "nickname": 65642 6 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/name.last.json: -------------------------------------------------------------------------------- 1 | { 2 | "last": 65125431 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/name.middle.json: -------------------------------------------------------------------------------- 1 | { 2 | "middle": 65145134 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/name.nickname.json: -------------------------------------------------------------------------------- 1 | { 2 | "nickname": [] 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Identity/name.username.json: -------------------------------------------------------------------------------- 1 | { 2 | "username": {} 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Meta/expirationDate.json: -------------------------------------------------------------------------------- 1 | { 2 | "expiry": 4514 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Meta/issuanceDate.json: -------------------------------------------------------------------------------- 1 | { 2 | "issued": 541324 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Meta/issuer.json: -------------------------------------------------------------------------------- 1 | { 2 | "issuer": 5641342 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Random/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": 45613245 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.city.json: -------------------------------------------------------------------------------- 1 | { 2 | "city": 561435 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.country.json: -------------------------------------------------------------------------------- 1 | { 2 | "country": 1543134 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.county.json: -------------------------------------------------------------------------------- 1 | { 2 | "county": "CJ5Wkf87dm", 3 | "anotherProperty": "gafgad" 4 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.json: -------------------------------------------------------------------------------- 1 | { 2 | "street": 4514, 3 | "unit": "7bwIUsixzn", 4 | "city": "WKui0bMTIN", 5 | "zipCode": "B5Uyc7bbOt", 6 | "state": "ST2LrahCPO", 7 | "county": "cnZTMsdZgQ", 8 | "country": "tAKNZFwqBV" 9 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.state.json: -------------------------------------------------------------------------------- 1 | { 2 | "state": 541543 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.street.json: -------------------------------------------------------------------------------- 1 | { 2 | "street": 45153 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.unit.json: -------------------------------------------------------------------------------- 1 | { 2 | "unit": 6542 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/address.zipCode.json: -------------------------------------------------------------------------------- 1 | { 2 | "zipCode": 451342 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/date.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": "16.887190847842405", 3 | "month": 4.33208397343556, 4 | "year": 1910.8122881975623 5 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/day.json: -------------------------------------------------------------------------------- 1 | { 2 | "day": "42.60887321150133" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/documentNumber.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentNumber": "4561543" 3 | } 4 | -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/documentType.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentType": 4561543 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/email.domain.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": 5641435 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/email.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": 54562, 3 | "domain": "IhsNoyWzhn" 4 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/email.user.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": 65254 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/image.image.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": 5462564 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/image.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": 56245, 3 | "md5": "zjSRherUuA" 4 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/image.md5.json: -------------------------------------------------------------------------------- 1 | { 2 | "md5": 564254 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/month.json: -------------------------------------------------------------------------------- 1 | { 2 | "month": "25.440331784890937" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/phone.countryCode.json: -------------------------------------------------------------------------------- 1 | { 2 | "countryCode": 56254 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/phone.json: -------------------------------------------------------------------------------- 1 | { 2 | "number": 56254, 3 | "countryCode": "OglxhaFT63" 4 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/phone.number.json: -------------------------------------------------------------------------------- 1 | { 2 | "number": 562 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/shortToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "shortToken": 1299 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Type/year.json: -------------------------------------------------------------------------------- 1 | { 2 | "year": "34.51072551849506" 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Verify/email.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": 5641435 3 | } -------------------------------------------------------------------------------- /__integrations__/fixtures/incorrect/Verify/phoneNumber.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": 562154 3 | } -------------------------------------------------------------------------------- /__test__/CredentialSignerVerifier.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | const { HDNode } = require('bitcoinjs-lib'); 4 | const CredentialSignerVerifier = require('../src/creds/CredentialSignerVerifier'); 5 | 6 | const SEED = 'f6d466fd58c20ff964673522083efebf'; 7 | const prvBase58 = 'xprv9s21ZrQH143K4aBUwUW6GVec7Y6oUEBqrt2WWaXyxjh2pjofNc1of44BLufn4p1t7Jq4EPzm5C9sRxCuBYJdHu62jhgfyPm544sNjtH7x8S'; 8 | 9 | const pubBase58 = 'xpub661MyMwAqRbcH4Fx3W36ddbLfZwHsguhE6x7JxwbX5E1hY8ov9L4CrNfCCQpV8pVK64CVqkhYQ9QLFgkVAUqkRThkTY1R4GiWHNZtAFSVpD'; 10 | 11 | describe('CredentialSignerVerifier Tests', () => { 12 | describe('Using a ECKeyPair', () => { 13 | let keyPair; 14 | let signerVerifier; 15 | 16 | beforeAll(() => { 17 | keyPair = HDNode.fromSeedHex(SEED); 18 | signerVerifier = new CredentialSignerVerifier({ keyPair }); 19 | }); 20 | 21 | it('Should sign and verify', () => { 22 | const toSign = { merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' }; 23 | const signature = signerVerifier.sign(toSign); 24 | expect(signature).toBeDefined(); 25 | const toVerify = { 26 | proof: { 27 | ...toSign, 28 | merkleRootSignature: signature, 29 | }, 30 | }; 31 | expect(signerVerifier.isSignatureValid(toVerify)).toBeTruthy(); 32 | }); 33 | 34 | it('Should verify', () => { 35 | const toVerify = { 36 | proof: { 37 | merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b666', 38 | merkleRootSignature: { 39 | algo: 'ec256k1', 40 | pubBase58: 'xpub661MyMwAqRbcH4Fx3W36ddbLfZwHsguhE6x7JxwbX5E1hY8ov9L4CrNfCCQpV8pVK64CVqkhYQ9QLFgkVAUqkRThkTY1R4GiWHNZtAFSVpD', 41 | signature: '3045022100e7f0921491e8da2759b24047443325483ac023795683dc3b91c78d0566a1159602206fd4e80982fd83705932543d02bc6abd079446bf4ec7b5d9fba4f7f5363bd6fa', 42 | }, 43 | }, 44 | }; 45 | 46 | expect(signerVerifier.isSignatureValid(toVerify)).toBeTruthy(); 47 | }); 48 | 49 | it('Should not verify', () => { 50 | const toVerify = { 51 | proof: { 52 | merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b666', 53 | merkleRootSignature: { 54 | algo: 'ec256k1', 55 | pubBase58: 'xpub661MyMwAqRbcH4Fx3W36ddbLfZwHsguhE6x7JxwbX5E1hY8ov9L4CrNfCCQpV8pVK64CVqkhYQ9QLFgkVAUqkRThkTY1R4GiWHNZtAFSVpD', 56 | signature: 'fa3e022100e7f0921491e8da2759b24047443325483ac023795683dc3b91c78d0566a1159602206fd4e80982fd83705932543d02bc6abd079446bf4ec7b5d9fba4f7f5363bd6fa', 57 | }, 58 | }, 59 | }; 60 | expect(signerVerifier.isSignatureValid(toVerify)).toBeFalsy(); 61 | }); 62 | }); 63 | describe('Using a prvBase58', () => { 64 | let signerVerifier; 65 | 66 | beforeAll(() => { 67 | signerVerifier = new CredentialSignerVerifier({ prvBase58 }); 68 | }); 69 | 70 | it('Should sign and verify', () => { 71 | const toSign = { merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' }; 72 | const signature = signerVerifier.sign(toSign); 73 | expect(signature).toBeDefined(); 74 | const toVerify = { 75 | proof: { 76 | ...toSign, 77 | merkleRootSignature: signature, 78 | }, 79 | }; 80 | expect(signerVerifier.isSignatureValid(toVerify)).toBeTruthy(); 81 | }); 82 | 83 | it('Should verify', () => { 84 | const toVerify = { 85 | proof: { 86 | merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b666', 87 | merkleRootSignature: { 88 | algo: 'ec256k1', 89 | pubBase58: 'xpub661MyMwAqRbcH4Fx3W36ddbLfZwHsguhE6x7JxwbX5E1hY8ov9L4CrNfCCQpV8pVK64CVqkhYQ9QLFgkVAUqkRThkTY1R4GiWHNZtAFSVpD', 90 | signature: '3045022100e7f0921491e8da2759b24047443325483ac023795683dc3b91c78d0566a1159602206fd4e80982fd83705932543d02bc6abd079446bf4ec7b5d9fba4f7f5363bd6fa', 91 | }, 92 | }, 93 | }; 94 | expect(signerVerifier.isSignatureValid(toVerify)).toBeTruthy(); 95 | }); 96 | 97 | it('Should not verify', () => { 98 | const toVerify = { 99 | proof: { 100 | merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b666', 101 | merkleRootSignature: { 102 | algo: 'ec256k1', 103 | pubBase58: 'xpub661MyMwAqRbcH4Fx3W36ddbLfZwHsguhE6x7JxwbX5E1hY8ov9L4CrNfCCQpV8pVK64CVqkhYQ9QLFgkVAUqkRThkTY1R4GiWHNZtAFSVpD', 104 | signature: 'fa3e022100e7f0921491e8da2759b24047443325483ac023795683dc3b91c78d0566a1159602206fd4e80982fd83705932543d02bc6abd079446bf4ec7b5d9fba4f7f5363bd6fa', 105 | }, 106 | }, 107 | }; 108 | expect(signerVerifier.isSignatureValid(toVerify)).toBeFalsy(); 109 | }); 110 | }); 111 | describe('Using a pubBase58', () => { 112 | let signerVerifier; 113 | 114 | beforeAll(() => { 115 | signerVerifier = new CredentialSignerVerifier({ pubBase58 }); 116 | }); 117 | 118 | it('Should verify', () => { 119 | const toVerify = { 120 | proof: { 121 | merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b666', 122 | merkleRootSignature: { 123 | algo: 'ec256k1', 124 | pubBase58: 'xpub661MyMwAqRbcH4Fx3W36ddbLfZwHsguhE6x7JxwbX5E1hY8ov9L4CrNfCCQpV8pVK64CVqkhYQ9QLFgkVAUqkRThkTY1R4GiWHNZtAFSVpD', 125 | signature: '3045022100e7f0921491e8da2759b24047443325483ac023795683dc3b91c78d0566a1159602206fd4e80982fd83705932543d02bc6abd079446bf4ec7b5d9fba4f7f5363bd6fa', 126 | }, 127 | }, 128 | }; 129 | expect(signerVerifier.isSignatureValid(toVerify)).toBeTruthy(); 130 | }); 131 | 132 | it('Should not verify', () => { 133 | const toVerify = { 134 | proof: { 135 | merkleRoot: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b666', 136 | merkleRootSignature: { 137 | algo: 'ec256k1', 138 | pubBase58: 'xpub661MyMwAqRbcH4Fx3W36ddbLfZwHsguhE6x7JxwbX5E1hY8ov9L4CrNfCCQpV8pVK64CVqkhYQ9QLFgkVAUqkRThkTY1R4GiWHNZtAFSVpD', 139 | signature: 'fa3e022100e7f0921491e8da2759b24047443325483ac023795683dc3b91c78d0566a1159602206fd4e80982fd83705932543d02bc6abd079446bf4ec7b5d9fba4f7f5363bd6fa', 140 | }, 141 | }, 142 | }; 143 | expect(signerVerifier.isSignatureValid(toVerify)).toBeFalsy(); 144 | }); 145 | }); 146 | }); 147 | -------------------------------------------------------------------------------- /__test__/SecureRandom.test.js: -------------------------------------------------------------------------------- 1 | const SecureRandom = require('../src/SecureRandom'); 2 | 3 | describe('Secure Random Tests', () => { 4 | it('should generate an random word', () => { 5 | const secureRandom = new SecureRandom(); 6 | const random = secureRandom.wordWith(16); 7 | expect(random).toBeDefined(); 8 | expect(random).toHaveLength(16); 9 | }); 10 | 11 | it('should initialize with seed', () => { 12 | try { 13 | const secureRandom = new SecureRandom('asdasd'); 14 | const random = secureRandom.wordWith(16); 15 | expect(random).toBeDefined(); 16 | expect(random).toHaveLength(16); 17 | } catch (e) { 18 | expect(e).toBeDefined(); 19 | expect(e.message).toBe("generator isn't seeded"); 20 | } 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /__test__/SecureRandomMock.test.js: -------------------------------------------------------------------------------- 1 | const SecureRandom = require('../src/SecureRandom'); 2 | // jest babel hoist the mock to the top of the file 3 | // do not mock the other SecureRandom.test.js or else you won't be able to unmock 4 | jest.mock('crypto'); 5 | describe('Secure Random Tests', () => { 6 | it('should fail since we are mocking the crypto class', () => { 7 | const secureRandom = new SecureRandom(); 8 | expect(() => secureRandom.wordWith(16)).toThrow(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /__test__/aggregate.test.js: -------------------------------------------------------------------------------- 1 | const CredentialCommons = require('../src/index'); 2 | 3 | describe('CredentialCommons.aggregate', () => { 4 | it('should throw Invalid Operator', () => { 5 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 6 | expect(() => { 7 | CredentialCommons.aggregate(collection, [{ $toString: null }]); 8 | }).toThrow('Invalid operator: $toString'); 9 | }); 10 | 11 | it('should return a collection with same equality', () => { 12 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 13 | const result = CredentialCommons.aggregate(collection, [{ none: null }]); 14 | expect(result).toStrictEqual(collection); 15 | }); 16 | 17 | it('should return the first 2 elements only', () => { 18 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 19 | const result = CredentialCommons.aggregate(collection, [{ $limit: 2 }]); 20 | expect(result).toStrictEqual([{ k: 'a' }, { k: 'b' }]); 21 | }); 22 | 23 | it('should return the first elements only', () => { 24 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 25 | const result = CredentialCommons.aggregate(collection, [{ $first: 'true' }]); 26 | expect(result).toStrictEqual([{ k: 'a' }]); 27 | }); 28 | 29 | it('should return the last elements only', () => { 30 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 31 | const result = CredentialCommons.aggregate(collection, [{ $last: 'true' }]); 32 | expect(result).toStrictEqual([{ k: 'c' }]); 33 | }); 34 | 35 | it('should return in ascending order ', () => { 36 | const collection = [{ k: 'b' }, { k: 'a' }, { k: 'c' }]; 37 | const result = CredentialCommons.aggregate(collection, [{ $sort: { k: 'ASC' } }]); 38 | expect(result).toStrictEqual([{ k: 'a' }, { k: 'b' }, { k: 'c' }]); 39 | }); 40 | 41 | it('should return in descending order ', () => { 42 | const collection = [{ k: 'b' }, { k: 'a' }, { k: 'c' }]; 43 | const result = CredentialCommons.aggregate(collection, [{ $sort: { k: 'DES' } }]); 44 | expect(result).toStrictEqual([{ k: 'c' }, { k: 'b' }, { k: 'a' }]); 45 | }); 46 | 47 | it('should apply operations in order', () => { 48 | const collection = [{ k: 'b' }, { k: 'a' }, { k: 'c' }]; 49 | const result = CredentialCommons.aggregate(collection, [ 50 | { $sort: { k: 'DES' } }, 51 | { $limit: 2 }]); 52 | expect(result).toStrictEqual([{ k: 'c' }, { k: 'b' }]); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /__test__/claim/UserCollectableAttributesWithMockedDefinitions.js: -------------------------------------------------------------------------------- 1 | const Claim = require('../../src/claim/Claim'); 2 | 3 | describe('Claim Constructions tests', () => { 4 | test('Wrong type', () => { 5 | const identifier = 'myMockedId'; 6 | const value = { 7 | country: 'DE', 8 | state: 'Berlin', 9 | county: 'Berlin', 10 | city: 'Berlin', 11 | postalCode: '15123', 12 | street: 'Ruthllardstr', 13 | unit: '12', 14 | }; 15 | try { 16 | const uca = new Claim(identifier, value); 17 | expect(uca).toBe('Should not pass here'); 18 | } catch (e) { 19 | expect(e).toBeDefined(); 20 | expect(e.message).toBe(`${JSON.stringify(value)} is not valid for ${identifier}`); 21 | } 22 | }); 23 | 24 | test('Get all properties of a String type', () => { 25 | const properties = Claim.getAllProperties('my:Mocked:Id2'); 26 | expect(properties).toBeInstanceOf(Array); 27 | expect(properties.length).toBe(1); 28 | expect(properties[0]).toBe('mocked.Id2'); 29 | }); 30 | 31 | test('Creating Claim from a Boolean type', () => { 32 | const identifier = 'my:Mocked:Id3'; 33 | const value = true; 34 | const uca = new Claim(identifier, value); 35 | expect(uca).toBeDefined(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /__test__/creds/fixtures/Cred1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "3636227c-5adf-4135-b81c-6dd1da53fd67", 3 | "issuer": "", 4 | "issuanceDate": "2018-11-13T18:54:11.665Z", 5 | "identifier": "credential-cvc:Email-v3", 6 | "version": "1", 7 | "type": [ 8 | "VerifiableCredential", 9 | "IdentityCredential" 10 | ], 11 | "credentialSubject": { 12 | "id": "did:sol:J2vss1hB3kgEfQMSSdvvjwRm3JdyFWp7S7dbX5mudS4V", 13 | "contact": { 14 | "email": { 15 | "domain": { 16 | "name": "UTpHKFyaaB", 17 | "tld": "oVaPsceZ4C" 18 | }, 19 | "username": "ZcMpCBQ0lE" 20 | } 21 | } 22 | }, 23 | "proof": { 24 | "type": "CvcMerkleProof2018", 25 | "merkleRoot": "7f62f719275f47331782c57d98e138c2c063065476f73a38c99023ddf9009287", 26 | "anchor": "TBD (Civic Blockchain Attestation)", 27 | "leaves": [ 28 | { 29 | "identifier": "claim-cvc:Contact.email-v1", 30 | "value": "urn:email.domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaaB|urn:email.domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|urn:email.username:705e41988a3659d943eeaaa5e6c91cc8de401674c4e130a7c44f5b4b2e8d7736:ZcMpCBQ0lE|", 31 | "claimPath": "contact.email", 32 | "targetHash": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7", 33 | "node": [ 34 | { 35 | "right": "e3662aeff5df76f0a694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7" 36 | }, 37 | { 38 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 39 | }, 40 | { 41 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 42 | }, 43 | { 44 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 45 | }, 46 | { 47 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 48 | } 49 | ] 50 | }, 51 | { 52 | "identifier": "claim-cvc:Email.domain-v1", 53 | "value": "urn:domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaaB|urn:domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|", 54 | "claimPath": "contact.email.domain", 55 | "targetHash": "e3662aeff5df76f0a694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7", 56 | "node": [ 57 | { 58 | "left": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7" 59 | }, 60 | { 61 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 62 | }, 63 | { 64 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 65 | }, 66 | { 67 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 68 | }, 69 | { 70 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 71 | } 72 | ] 73 | }, 74 | { 75 | "identifier": "cvc:Meta:issuer", 76 | "value": "urn:issuer:3c1d9cc9f8bd5dd7f4845c18017c559ecee758c6dc2f5a3b63385bf3f681e13a:|", 77 | "claimPath": "meta.issuer", 78 | "targetHash": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b", 79 | "node": [ 80 | { 81 | "right": "2820718fc34e3e07c40c4c0c0985937a193a63839695768f38630acfbecaf85d" 82 | }, 83 | { 84 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 85 | }, 86 | { 87 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 88 | }, 89 | { 90 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 91 | }, 92 | { 93 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 94 | } 95 | ] 96 | }, 97 | { 98 | "identifier": "cvc:Meta:issuanceDate", 99 | "value": "urn:issuanceDate:0029acb02ff26faf7775883957e9a5271b358f56734496b7ffde2760ace9ddce:2018-11-13T18:54:11.665Z|", 100 | "claimPath": "meta.issuanceDate", 101 | "targetHash": "2820718fc34e3e07c40c4c0c0985937a193a63839695768f38630acfbecaf85d", 102 | "node": [ 103 | { 104 | "left": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b" 105 | }, 106 | { 107 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 108 | }, 109 | { 110 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 111 | }, 112 | { 113 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 114 | }, 115 | { 116 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 117 | } 118 | ] 119 | }, 120 | { 121 | "identifier": "cvc:Meta:expirationDate", 122 | "value": "urn:expirationDate:f437c1d530d5422b3df947b7d97da82c5abfee582c1be15bd2900ff35e8d0624:null|", 123 | "claimPath": "meta.expirationDate", 124 | "targetHash": "c73ce4be4e264f366dfc8a95abf7e507e75d13a2a06af5e50d2dc09e6c71d9cd", 125 | "node": [ 126 | { 127 | "right": "8c741ed5a929697f02cfb47019d1e60ed038ac40b4f32ef52ae48ea0fa93c0fe" 128 | }, 129 | { 130 | "right": "9740db43522f2170c4ad18230f53ac4dbdb9f7e423687e320767b569d6ee12be" 131 | }, 132 | { 133 | "left": "63866d32feddce9393a91d54b85d370c5cfc38641ce3b4db2df73499b9347918" 134 | }, 135 | { 136 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 137 | }, 138 | { 139 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 140 | } 141 | ] 142 | } 143 | ], 144 | "granted": null 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /__test__/creds/fixtures/Email.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "e3dc1ceb-3899-454f-a80c-52c97a0cc9d8", 3 | "issuer": "jest:test:fe07c3d0-e8b0-11e8-8a40-7fe4d191eb47", 4 | "issuanceDate": "2018-11-15T08:32:30.862Z", 5 | "identifier": "credential-cvc:Email-v3", 6 | "version": "1", 7 | "type": [ 8 | "VerifiableCredential", 9 | "IdentityCredential" 10 | ], 11 | "credentialSubject": { 12 | "id": "did:sol:J2vss1hB3kgEfQMSSdvvjwRm3JdyFWp7S7dbX5mudS4V", 13 | "contact": { 14 | "email": { 15 | "domain": { 16 | "name": "X6gQFO3QYg", 17 | "tld": "PSsiuGIgez" 18 | }, 19 | "username": "b6J7B5pCWo" 20 | } 21 | } 22 | }, 23 | "proof": { 24 | "type": "CvcMerkleProof2018", 25 | "merkleRoot": "03e9bccbf5109b7b70154eddd95b089a24896d0a6b46f52549d8471febd83a3d", 26 | "anchor": { 27 | "subject": { 28 | "pub": "xpub:dummy", 29 | "label": "credential-cvc:Email-v1", 30 | "data": "03e9bccbf5109b7b70154eddd95b089a24896d0a6b46f52549d8471febd83a3d", 31 | "signature": "signed:dummy" 32 | }, 33 | "walletId": "none", 34 | "cosigners": [ 35 | { 36 | "pub": "xpub:dummy" 37 | }, 38 | { 39 | "pub": "xpub:dummy" 40 | } 41 | ], 42 | "authority": { 43 | "pub": "xpub:dummy", 44 | "path": "/" 45 | }, 46 | "coin": "dummycoin", 47 | "tx": "", 48 | "network": "dummynet", 49 | "type": "permanent", 50 | "civicAsPrimary": false, 51 | "schema": "dummy-20180201", 52 | "value": {} 53 | }, 54 | "leaves": [ 55 | { 56 | "identifier": "claim-cvc:Contact.email-v1", 57 | "value": "urn:email.domain.name:d8ca1591c2526a1b03e8ab9be02f32036c112b1b347e3cd7ae6bf5079ab249a2:X6gQFO3QYg|urn:email.domain.tld:58f18dc6fe5a24b3626fbd9a03548864dc380114a17f346f0d97d3b9cb0700d5:PSsiuGIgez|urn:email.username:3e19732ba77e798b6b85f55e3d5321e58108c758b865614a60b3198fb10c0d69:b6J7B5pCWo|", 58 | "claimPath": "contact.email", 59 | "targetHash": "1952a3a7260b286d1251f40db511d9b5cf78960a414791c96ac6437b2968a190", 60 | "node": [ 61 | { 62 | "right": "5478af59d9d5633434dbcac0c4d98d65c3c23dd80fb008081aabd5c95ea40642" 63 | }, 64 | { 65 | "right": "070c1ad44f28450390cd89e482bc4b8af8a41b4b1a5e112d9218bea051f6ad26" 66 | }, 67 | { 68 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 69 | }, 70 | { 71 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 72 | }, 73 | { 74 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 75 | } 76 | ] 77 | }, 78 | { 79 | "identifier": "claim-cvc:Email.domain-v1", 80 | "value": "urn:domain.name:d8ca1591c2526a1b03e8ab9be02f32036c112b1b347e3cd7ae6bf5079ab249a2:X6gQFO3QYg|urn:domain.tld:58f18dc6fe5a24b3626fbd9a03548864dc380114a17f346f0d97d3b9cb0700d5:PSsiuGIgez|", 81 | "claimPath": "contact.email.domain", 82 | "targetHash": "5478af59d9d5633434dbcac0c4d98d65c3c23dd80fb008081aabd5c95ea40642", 83 | "node": [ 84 | { 85 | "left": "1952a3a7260b286d1251f40db511d9b5cf78960a414791c96ac6437b2968a190" 86 | }, 87 | { 88 | "right": "070c1ad44f28450390cd89e482bc4b8af8a41b4b1a5e112d9218bea051f6ad26" 89 | }, 90 | { 91 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 92 | }, 93 | { 94 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 95 | }, 96 | { 97 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 98 | } 99 | ] 100 | }, 101 | { 102 | "identifier": "cvc:Meta:issuer", 103 | "value": "urn:issuer:572ac63d41247d7b2cb3f8f344447b51e1898e11206b38750261250f976fbedf:jest:test:fe07c3d0-e8b0-11e8-8a40-7fe4d191eb47|", 104 | "claimPath": "meta.issuer", 105 | "targetHash": "3e2858af4f6365227b60e562e6633c48f4c11665e0f80454a88591c71d3b1983", 106 | "node": [ 107 | { 108 | "right": "d20fab7ea0835b15ce3bc78118f0a044ce1f2da4fcaf06f2df465964811168b0" 109 | }, 110 | { 111 | "left": "f4688dcbf2bcd091b274227f1ffcd7a55a125526871caeda08b9ca344303fec6" 112 | }, 113 | { 114 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 115 | }, 116 | { 117 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 118 | }, 119 | { 120 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 121 | } 122 | ] 123 | }, 124 | { 125 | "identifier": "cvc:Meta:issuanceDate", 126 | "value": "urn:issuanceDate:34618d06738b071a224f2cf0236def1022dcfaf23827b85050cf653d27001635:2018-11-15T08:32:30.862Z|", 127 | "claimPath": "meta.issuanceDate", 128 | "targetHash": "d20fab7ea0835b15ce3bc78118f0a044ce1f2da4fcaf06f2df465964811168b0", 129 | "node": [ 130 | { 131 | "left": "3e2858af4f6365227b60e562e6633c48f4c11665e0f80454a88591c71d3b1983" 132 | }, 133 | { 134 | "left": "f4688dcbf2bcd091b274227f1ffcd7a55a125526871caeda08b9ca344303fec6" 135 | }, 136 | { 137 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 138 | }, 139 | { 140 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 141 | }, 142 | { 143 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 144 | } 145 | ] 146 | }, 147 | { 148 | "identifier": "cvc:Meta:expirationDate", 149 | "value": "urn:expirationDate:629bc2bb479244a518ead46215278d86241cf206a4c32d5fff0eff3ef9f881ab:null|", 150 | "claimPath": "meta.expirationDate", 151 | "targetHash": "56eb2aa57e7d904e37bbe4cf4d9e34cd068ceeb1a18fd09d7be56bc9f715dfd0", 152 | "node": [ 153 | { 154 | "right": "856e21db11d11e74c7ca39b02adb7373283eaf205670b11a9dec9dc03f97c606" 155 | }, 156 | { 157 | "right": "740f2a0682cca1c44a1973a81fa24c3eaf81cb50f4effdcc7b1d76bc0f9da60c" 158 | }, 159 | { 160 | "left": "5cb4049edfe5a169032dbb4a66d01c59c64b50ef7d40ec2690d24429afd87ea4" 161 | }, 162 | { 163 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 164 | }, 165 | { 166 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 167 | } 168 | ] 169 | } 170 | ], 171 | "granted": null 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /__test__/creds/fixtures/PermanentAnchor.json: -------------------------------------------------------------------------------- 1 | { 2 | "subject": { 3 | "pub": "xpub:dummy", 4 | "label": "test1530668445601", 5 | "data": "test1530668445601", 6 | "signature": "304402204e4521f4f49baf55fb85539a2e8897e4fb05fad8bed6418e793d952ea63d559f02200f1a65d43392efe6e4388ced8694097333224685676e2c954c76efdbf87d4b55" 7 | }, 8 | "walletId": "5b3c25ae531deca003af947456de0316", 9 | "cosigners": [{ 10 | "pub": "xpub:dummy" 11 | }, { 12 | "pub": "xpub:dummy" 13 | }], 14 | "authority": { 15 | "pub": "xpub:dummy", 16 | "path": "/" 17 | }, 18 | "coin": "dummycoin", 19 | "tx": "d42108e60e941483045022100bd2fe1e1958424dddfac818c1cb9cf9b4b0758bff0165dafcb6ca3fb935864b80220621f79767d8b4a144f0b371ece12704eadc4d7cf60a23687d156fffdce9f76a3414c69522102896c0bad1cba92ff30e93a3301dcaed0c4a188e3a60e1b0abc64e572b38a70a12103f53ac90200000001ac0bacc5039e659e5a22365ca5f45f6f6f43b97c7d21812f457ca8a73122dcde00000000fdfd000047304402203cdac186e4678ce837b7acffbb769740fb440b419f237b407303858b3d29e4ed02204b62e3a5071bbca7c81581ced96d519b24d39114bedc13405fa81eac48ba895619b56825e473e7b5bb72a1c473a8f3bd0000000092bf025bf8da001210261d79a240feb1ba9642068856f928e3bd21985a443631007fed2fbed8d067c5353aeffffffff02db497d0f0000000017a914f7e370d5d2af95e058985724a4fe7c2c175f423087fb1700000000000017a914cd14854e02d273af9612ae649e7d13a2f73fcfde87", 20 | "network": "dummynet", 21 | "value": 259876034, 22 | "type": "permanent", 23 | "civicAsPrimary": false, 24 | "schema": "dummy-20180201" 25 | } -------------------------------------------------------------------------------- /__test__/creds/fixtures/TempAnchor.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": "dummy-20180201", 3 | "tx": "01000000018815822815dbd6c355ad40da1f2fac328a408d538638143177168b57af5d753a00000000fc004730440220424268275da66825bc99a3f487472baa0751b67355407b4a4e99da04a3186c520220578b820dd051c919c2fb57b26aa29667483b547f6766a23e3c821e47a5d1237b0147304402201316cc0ee8a968f4d86a616fcf710b663e0bb7021e95d7a300036b65e95ca34602204f05162db06278af2a8abdd7ab4d92e973dc4154a92bf37a4056f3298fa9ecad014c695221028f9205846d9b23dd9a17588ae13603aa3eda3599582750904716c827d02269db210340f8f56a56b2af2a9698f66574882068cf8bd8fa95a26136ac34edabfe5eb5d021029d52d336232eb3d4f37730822df9d3993a84c3edba20f14d3ee0f20141c0bdfd53aeffffffff01551500000000000017a91460312cbbb8ec560305a239d56398f0d8aa57ecf68700000000", 4 | "subject": { 5 | "label": "teste", 6 | "pub": "xpub:dummy", 7 | "data": "testesdsd", 8 | "signature": "304502210089e94f11587bf7fa202817ace9664639855a146565d4e54b9f853f31f4d7ce31022077098a904e0dda7ab947db92a3e7dd7a5d52654c286151c3cc97feb0ef4a3310" 9 | }, 10 | "authority": { 11 | "pub": "xpub:dummy", 12 | "path": "/1/0/0/0" 13 | }, 14 | "cosigners": [{ 15 | "pub": "xpub:dummy" 16 | }, 17 | { 18 | "pub": "xpub:dummy" 19 | } 20 | ], 21 | "type": "temporary", 22 | "network": "dummynet" 23 | } -------------------------------------------------------------------------------- /__test__/creds/fixtures/VCWithTamperedLeafValue.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "3636227c-5adf-4135-b81c-6dd1da53fd67", 3 | "issuer": "", 4 | "issuanceDate": "2018-11-13T18:54:11.665Z", 5 | "identifier": "credential-cvc:Email-v3", 6 | "type": [ 7 | "VerifiableCredential", 8 | "IdentityCredential" 9 | ], 10 | "credentialSubject": { 11 | "id": "did:sol:J2vss1hB3kgEfQMSSdvvjwRm3JdyFWp7S7dbX5mudS4V", 12 | "contact": { 13 | "email": { 14 | "domain": { 15 | "name": "UTpHKFyaaB", 16 | "tld": "oVaPsceZ4C" 17 | }, 18 | "username": "ZcMpCBQ0lE" 19 | } 20 | } 21 | }, 22 | "proof": { 23 | "type": "CvcMerkleProof2018", 24 | "merkleRoot": "7f62f719275f47331782c57d98e138c2c063065476f73a38c99023ddf9009287", 25 | "anchor": "TBD (Civic Blockchain Attestation)", 26 | "leaves": [ 27 | { 28 | "identifier": "claim-cvc:Contact.email-v1", 29 | "value": "urn:email.domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaB|urn:email.domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|urn:email.username:705e41988a3659d943eeaaa5e6c91cc8de401674c4e130a7c44f5b4b2e8d7736:ZcMpCBQ0lE|", 30 | "claimPath": "contact.email", 31 | "targetHash": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7", 32 | "node": [ 33 | { 34 | "right": "e3662aeff5df76694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7" 35 | }, 36 | { 37 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 38 | }, 39 | { 40 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 41 | }, 42 | { 43 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 44 | }, 45 | { 46 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 47 | } 48 | ] 49 | }, 50 | { 51 | "identifier": "claim-cvc:Email.domain-v1", 52 | "value": "urn:domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaaB|urn:domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|", 53 | "claimPath": "contact.email.domain", 54 | "targetHash": "e3662aeff5df76f0a694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7", 55 | "node": [ 56 | { 57 | "left": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7" 58 | }, 59 | { 60 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 61 | }, 62 | { 63 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 64 | }, 65 | { 66 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 67 | }, 68 | { 69 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 70 | } 71 | ] 72 | }, 73 | { 74 | "identifier": "cvc:Meta:issuer", 75 | "value": "urn:issuer:3c1d9cc9f8bd5dd7f4845c18017c559ecee758c6dc2f5a3b63385bf3f681e13a:|", 76 | "claimPath": "meta.issuer", 77 | "targetHash": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b", 78 | "node": [ 79 | { 80 | "right": "2820718fc34e3e07c40c4c0c0985937a193a63839695768f38630acfbecaf85d" 81 | }, 82 | { 83 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 84 | }, 85 | { 86 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 87 | }, 88 | { 89 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 90 | }, 91 | { 92 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 93 | } 94 | ] 95 | }, 96 | { 97 | "identifier": "cvc:Meta:issuanceDate", 98 | "value": "urn:issuanceDate:0029acb02ff26faf7775883957e9a5271b358f56734496b7ffde2760ace9ddce:2018-11-13T18:54:11.665Z|", 99 | "claimPath": "meta.issuanceDate", 100 | "targetHash": "2820718fc34e3e07c40c4c0c098937a193a63839695768f38630acfbecaf85d", 101 | "node": [ 102 | { 103 | "left": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b" 104 | }, 105 | { 106 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 107 | }, 108 | { 109 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 110 | }, 111 | { 112 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 113 | }, 114 | { 115 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 116 | } 117 | ] 118 | }, 119 | { 120 | "identifier": "cvc:Meta:expirationDate", 121 | "value": "urn:expirationDate:f437c1d530d5422b3df947b7d97da82c5abfee582c1be15bd2900ff35e8d0624:null|", 122 | "claimPath": "meta.expirationDate", 123 | "targetHash": "c73ce4be4e264f366dfc8a95abf7e507e75d13a2a06af5e50d2dc09e6c71d9cd", 124 | "node": [ 125 | { 126 | "right": "8c741ed5a929697f02cfb47019d1e60ed038ac40b4f32ef52ae48ea0fa93c0fe" 127 | }, 128 | { 129 | "right": "9740db43522f2170c4ad18230f53ac4dbdb9f7e423687e320767b569d6ee12be" 130 | }, 131 | { 132 | "left": "63866d32feddce9393a91d54b85d370c5cfc38641ce3b4db2df73499b9347918" 133 | }, 134 | { 135 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 136 | }, 137 | { 138 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 139 | } 140 | ] 141 | } 142 | ], 143 | "granted": null 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /__test__/creds/fixtures/emailCredentialOld.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "@context": [ 4 | "https://www.w3.org/2018/credentials/v1", 5 | "https://www.identity.com/credentials/v3" 6 | ], 7 | "id": "852854bf-86aa-47a8-8570-6911b439342b", 8 | "identifier": "credential-cvc:Email-v3", 9 | "issuer": "did:sol:tid652xmv91UHLW3HKnQSYMoNYko6FWd8sUEuYF5LPn", 10 | "issuanceDate": "2023-02-02T13:12:39.394Z", 11 | "type": [ 12 | "VerifiableCredential", 13 | "IdentityCredential" 14 | ], 15 | "credentialSubject": { 16 | "id": "did:sol:QuhsMqH2DTCUSYkCdvE9fcaq7pER7iYd8BRJmdBpwEC", 17 | "contact": { 18 | "email": { 19 | "domain": { 20 | "name": "civic", 21 | "tld": "com" 22 | }, 23 | "username": "lucas" 24 | } 25 | } 26 | }, 27 | "proof": { 28 | "type": "CvcMerkleProof2018", 29 | "merkleRoot": "0152d816dc649aea82473cdb7467de9eecd6dafb5bc72059d7d92ea012dbf6dd", 30 | "anchor": "TBD (Civic Blockchain Attestation)", 31 | "leaves": [ 32 | { 33 | "identifier": "claim-cvc:Contact.email-v1", 34 | "value": "urn:email.domain.name:56a8b5dc58caa0ed416a82eb48cbf7e1dee4449e6a289839037ccf7a79be0f61:civic|urn:email.domain.tld:92c4c27240f59ff2e1cf02e8d34c406f54f9ca3ebd802719354fb5081a9beca5:com|urn:email.username:85018d3234c84b7adc22cfc0682c9610b0ed2e7d2f9fd8d0bc73cc2d823d089a:lucas|", 35 | "claimPath": "contact.email", 36 | "targetHash": "5e9773b0433acea7e150f5d62a716789a1679d7fdc69910b55b0b462811da8ba", 37 | "node": [ 38 | { 39 | "right": "2c19051202e3da553836b89f16646fbf718be0d84090484b3840589aeedab66b" 40 | }, 41 | { 42 | "right": "e3ef4f46b4f635bac2fab6b779510e97a7d4f1b18374de4089edc9fc4c4a25ed" 43 | }, 44 | { 45 | "right": "bd4f9f71c2b6b93e6641e11b781e5188c24641952f9690bba80fc16a66f224c9" 46 | }, 47 | { 48 | "right": "7ddd7075dc704b653d1f24cec85114f743e593f88ab6bcb8217434b9bedab489" 49 | }, 50 | { 51 | "right": "3c69f2bb8f4c402be9e2522bb1544b56d401b7ddb5fe263f71ee9f89d551ed83" 52 | } 53 | ] 54 | }, 55 | { 56 | "identifier": "claim-cvc:Email.domain-v1", 57 | "value": "urn:domain.name:56a8b5dc58caa0ed416a82eb48cbf7e1dee4449e6a289839037ccf7a79be0f61:civic|urn:domain.tld:92c4c27240f59ff2e1cf02e8d34c406f54f9ca3ebd802719354fb5081a9beca5:com|", 58 | "claimPath": "contact.email.domain", 59 | "targetHash": "2c19051202e3da553836b89f16646fbf718be0d84090484b3840589aeedab66b", 60 | "node": [ 61 | { 62 | "left": "5e9773b0433acea7e150f5d62a716789a1679d7fdc69910b55b0b462811da8ba" 63 | }, 64 | { 65 | "right": "e3ef4f46b4f635bac2fab6b779510e97a7d4f1b18374de4089edc9fc4c4a25ed" 66 | }, 67 | { 68 | "right": "bd4f9f71c2b6b93e6641e11b781e5188c24641952f9690bba80fc16a66f224c9" 69 | }, 70 | { 71 | "right": "7ddd7075dc704b653d1f24cec85114f743e593f88ab6bcb8217434b9bedab489" 72 | }, 73 | { 74 | "right": "3c69f2bb8f4c402be9e2522bb1544b56d401b7ddb5fe263f71ee9f89d551ed83" 75 | } 76 | ] 77 | }, 78 | { 79 | "identifier": "cvc:Meta:issuer", 80 | "value": "urn:issuer:542609fea6749d154bec471a5140a004593f239417a082580e21485312637339:did:sol:tid652xmv91UHLW3HKnQSYMoNYko6FWd8sUEuYF5LPn|", 81 | "claimPath": "meta.issuer", 82 | "targetHash": "82c70faffba5e4507214549dd527c4a1f088ad65cf7cce6d53b83a38dbd6c64e", 83 | "node": [ 84 | { 85 | "right": "8c00eea4b9e4ff41013ac92b4bd7e9dd6a21e2a76ed31b930fd9de17325438dd" 86 | }, 87 | { 88 | "left": "a8dcbe1accb61ad409b19ff02129bef53df1c10e91b0f762885ccb433c6e7a9f" 89 | }, 90 | { 91 | "right": "bd4f9f71c2b6b93e6641e11b781e5188c24641952f9690bba80fc16a66f224c9" 92 | }, 93 | { 94 | "right": "7ddd7075dc704b653d1f24cec85114f743e593f88ab6bcb8217434b9bedab489" 95 | }, 96 | { 97 | "right": "3c69f2bb8f4c402be9e2522bb1544b56d401b7ddb5fe263f71ee9f89d551ed83" 98 | } 99 | ] 100 | }, 101 | { 102 | "identifier": "cvc:Meta:issuanceDate", 103 | "value": "urn:issuanceDate:9e1f567c70f07536bcf604a5f03fb9e2fe241871b579fa9757085a00e61d698f:2023-02-02T13:12:39.394Z|", 104 | "claimPath": "meta.issuanceDate", 105 | "targetHash": "8c00eea4b9e4ff41013ac92b4bd7e9dd6a21e2a76ed31b930fd9de17325438dd", 106 | "node": [ 107 | { 108 | "left": "82c70faffba5e4507214549dd527c4a1f088ad65cf7cce6d53b83a38dbd6c64e" 109 | }, 110 | { 111 | "left": "a8dcbe1accb61ad409b19ff02129bef53df1c10e91b0f762885ccb433c6e7a9f" 112 | }, 113 | { 114 | "right": "bd4f9f71c2b6b93e6641e11b781e5188c24641952f9690bba80fc16a66f224c9" 115 | }, 116 | { 117 | "right": "7ddd7075dc704b653d1f24cec85114f743e593f88ab6bcb8217434b9bedab489" 118 | }, 119 | { 120 | "right": "3c69f2bb8f4c402be9e2522bb1544b56d401b7ddb5fe263f71ee9f89d551ed83" 121 | } 122 | ] 123 | }, 124 | { 125 | "identifier": "cvc:Meta:expirationDate", 126 | "value": "urn:expirationDate:6b4f012ea5cfce84ca08c49941c64883a8d5955627b35c830a641b3e29ead7e0:null|", 127 | "claimPath": "meta.expirationDate", 128 | "targetHash": "978807d6506bc2748e7976c515df311e247be299b0d7237e3bea0e702b30fc7d", 129 | "node": [ 130 | { 131 | "right": "91dfdf2b1a4072f6316c2241d0cbd3b9efc9159f061d23b7f60f0f38bf7b3217" 132 | }, 133 | { 134 | "right": "17b28becc9cd28693064fb80120d8fd00e9150337db6d2f1b3b8767326c14274" 135 | }, 136 | { 137 | "left": "a92335740e6ad78e0dcd0758459a5b21f9fa62e462803cc939166d9380a590b1" 138 | }, 139 | { 140 | "right": "7ddd7075dc704b653d1f24cec85114f743e593f88ab6bcb8217434b9bedab489" 141 | }, 142 | { 143 | "right": "3c69f2bb8f4c402be9e2522bb1544b56d401b7ddb5fe263f71ee9f89d551ed83" 144 | } 145 | ] 146 | } 147 | ], 148 | "merkleRootSignature": { 149 | "signature": "a67f362f6e8ff8c7c11e832d1587c4e0bc22c669f2f3bd69c37603628fbc3db0c40840ffec74a4ce4deafc93980e652dbe7e0c938911d917287cbc0568b64b08", 150 | "verificationMethod": "did:sol:tid652xmv91UHLW3HKnQSYMoNYko6FWd8sUEuYF5LPn#default" 151 | }, 152 | "granted": null 153 | } 154 | } -------------------------------------------------------------------------------- /__test__/creds/fixtures/filteredIdDocument-v3.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "f471b5f8-6ad6-4782-968d-f2924145fa54", 3 | "issuer": "", 4 | "issuanceDate": "2021-05-26T20:11:12.082Z", 5 | "identifier": "credential-cvc:IdDocument-v3", 6 | "version": "1", 7 | "type": [ 8 | "VerifiableCredential", 9 | "IdentityCredential" 10 | ], 11 | "transient": false, 12 | "credentialSubject": { 13 | "id": "did:sol:J2vss1hB3kgEfQMSSdvvjwRm3JdyFWp7S7dbX5mudS4V", 14 | "document": { 15 | "dateOfBirth": { 16 | "day": 20, 17 | "month": 3, 18 | "year": 1978 19 | } 20 | } 21 | }, 22 | "proof": { 23 | "type": "CvcMerkleProof2018", 24 | "merkleRoot": "9d424cbc30d418ed42f1b1031fa4fdef273e6b371637b4c8e5184a566b9d27cc", 25 | "anchor": "TBD (Civic Blockchain Attestation)", 26 | "leaves": [ 27 | { 28 | "identifier": "claim-cvc:Document.dateOfBirth-v1", 29 | "value": "urn:dateOfBirth.day:f0bbfa2a35fc0dfa27a2620691feedde6fff1c522817b546e730740f7339354d:20|urn:dateOfBirth.month:75e6e5fa1f03d6b985862e7ad1467405e0c482df64e6ed1692312aaba7d4d951:3|urn:dateOfBirth.year:c4d7200e945ef41009be24127cdd394d17a7bc0330d3b1b19270372543ff6517:1978|", 30 | "claimPath": "document.dateOfBirth", 31 | "targetHash": "3fdb18a8022d009da8eda7b353ebfdaad91ad4d6256f647e174ac16448d42f6d", 32 | "node": [ 33 | { 34 | "left": "72e6f2e8c817048bb82442371202c9c078cabbacb7739ce4781f68855b362ca8" 35 | }, 36 | { 37 | "right": "aae76d0dd2b272496a4ccc799cd60a329da4d78742b9e4f8792c4a3b4259d414" 38 | }, 39 | { 40 | "right": "9c4a9d7c1d1a76dd3c8aa274d6cf8de8cd5ed4658162c84db409e8c0dab422ea" 41 | }, 42 | { 43 | "left": "03024ff54437b7d65ad908229977e8603f3f5451a611ec88235775db23d522f5" 44 | }, 45 | { 46 | "right": "b8dc070cacd5d604ec328cfee7d396e3a6ba5011a616049126d37460f7280154" 47 | } 48 | ] 49 | } 50 | ], 51 | "granted": null 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /__test__/creds/proxyFixtures/Cred1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "3636227c-5adf-4135-b81c-6dd1da53fd67", 3 | "issuer": "", 4 | "issuanceDate": "2018-11-13T18:54:11.665Z", 5 | "identifier": "credential-cvc:Email-v1", 6 | "expirationDate": null, 7 | "version": "1", 8 | "type": [ 9 | "Credential", 10 | "credential-cvc:Email-v1" 11 | ], 12 | "claim": { 13 | "contact": { 14 | "email": { 15 | "domain": { 16 | "name": "UTpHKFyaaB", 17 | "tld": "oVaPsceZ4C" 18 | }, 19 | "username": "ZcMpCBQ0lE" 20 | } 21 | } 22 | }, 23 | "proof": { 24 | "type": "CvcMerkleProof2018", 25 | "merkleRoot": "7f62f719275f47331782c57d98e138c2c063065476f73a38c99023ddf9009287", 26 | "anchor": "TBD (Civic Blockchain Attestation)", 27 | "leaves": [ 28 | { 29 | "identifier": "claim-cvc:Contact.email-v1", 30 | "value": "urn:email.domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaaB|urn:email.domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|urn:email.username:705e41988a3659d943eeaaa5e6c91cc8de401674c4e130a7c44f5b4b2e8d7736:ZcMpCBQ0lE|", 31 | "claimPath": "contact.email", 32 | "targetHash": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7", 33 | "node": [ 34 | { 35 | "right": "e3662aeff5df76f0a694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7" 36 | }, 37 | { 38 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 39 | }, 40 | { 41 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 42 | }, 43 | { 44 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 45 | }, 46 | { 47 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 48 | } 49 | ] 50 | }, 51 | { 52 | "identifier": "claim-cvc:Email.domain-v1", 53 | "value": "urn:domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaaB|urn:domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|", 54 | "claimPath": "contact.email.domain", 55 | "targetHash": "e3662aeff5df76f0a694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7", 56 | "node": [ 57 | { 58 | "left": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7" 59 | }, 60 | { 61 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 62 | }, 63 | { 64 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 65 | }, 66 | { 67 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 68 | }, 69 | { 70 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 71 | } 72 | ] 73 | }, 74 | { 75 | "identifier": "cvc:Meta:issuer", 76 | "value": "urn:issuer:3c1d9cc9f8bd5dd7f4845c18017c559ecee758c6dc2f5a3b63385bf3f681e13a:|", 77 | "claimPath": "meta.issuer", 78 | "targetHash": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b", 79 | "node": [ 80 | { 81 | "right": "2820718fc34e3e07c40c4c0c0985937a193a63839695768f38630acfbecaf85d" 82 | }, 83 | { 84 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 85 | }, 86 | { 87 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 88 | }, 89 | { 90 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 91 | }, 92 | { 93 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 94 | } 95 | ] 96 | }, 97 | { 98 | "identifier": "cvc:Meta:issuanceDate", 99 | "value": "urn:issuanceDate:0029acb02ff26faf7775883957e9a5271b358f56734496b7ffde2760ace9ddce:2018-11-13T18:54:11.665Z|", 100 | "claimPath": "meta.issuanceDate", 101 | "targetHash": "2820718fc34e3e07c40c4c0c0985937a193a63839695768f38630acfbecaf85d", 102 | "node": [ 103 | { 104 | "left": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b" 105 | }, 106 | { 107 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 108 | }, 109 | { 110 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 111 | }, 112 | { 113 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 114 | }, 115 | { 116 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 117 | } 118 | ] 119 | }, 120 | { 121 | "identifier": "cvc:Meta:expirationDate", 122 | "value": "urn:expirationDate:f437c1d530d5422b3df947b7d97da82c5abfee582c1be15bd2900ff35e8d0624:null|", 123 | "claimPath": "meta.expirationDate", 124 | "targetHash": "c73ce4be4e264f366dfc8a95abf7e507e75d13a2a06af5e50d2dc09e6c71d9cd", 125 | "node": [ 126 | { 127 | "right": "8c741ed5a929697f02cfb47019d1e60ed038ac40b4f32ef52ae48ea0fa93c0fe" 128 | }, 129 | { 130 | "right": "9740db43522f2170c4ad18230f53ac4dbdb9f7e423687e320767b569d6ee12be" 131 | }, 132 | { 133 | "left": "63866d32feddce9393a91d54b85d370c5cfc38641ce3b4db2df73499b9347918" 134 | }, 135 | { 136 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 137 | }, 138 | { 139 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 140 | } 141 | ] 142 | } 143 | ] 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /__test__/creds/proxyFixtures/Email.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "e3dc1ceb-3899-454f-a80c-52c97a0cc9d8", 3 | "issuer": "jest:test:fe07c3d0-e8b0-11e8-8a40-7fe4d191eb47", 4 | "issuanceDate": "2018-11-15T08:32:30.862Z", 5 | "identifier": "credential-cvc:Email-v1", 6 | "expirationDate": null, 7 | "version": "1", 8 | "type": [ 9 | "Credential", 10 | "credential-cvc:Email-v1" 11 | ], 12 | "claim": { 13 | "contact": { 14 | "email": { 15 | "domain": { 16 | "name": "X6gQFO3QYg", 17 | "tld": "PSsiuGIgez" 18 | }, 19 | "username": "b6J7B5pCWo" 20 | } 21 | } 22 | }, 23 | "proof": { 24 | "type": "CvcMerkleProof2018", 25 | "merkleRoot": "03e9bccbf5109b7b70154eddd95b089a24896d0a6b46f52549d8471febd83a3d", 26 | "anchor": { 27 | "subject": { 28 | "pub": "xpub:dummy", 29 | "label": "credential-cvc:Email-v1", 30 | "data": "03e9bccbf5109b7b70154eddd95b089a24896d0a6b46f52549d8471febd83a3d", 31 | "signature": "signed:dummy" 32 | }, 33 | "walletId": "none", 34 | "cosigners": [ 35 | { 36 | "pub": "xpub:dummy" 37 | }, 38 | { 39 | "pub": "xpub:dummy" 40 | } 41 | ], 42 | "authority": { 43 | "pub": "xpub:dummy", 44 | "path": "/" 45 | }, 46 | "coin": "dummycoin", 47 | "tx": "", 48 | "network": "dummynet", 49 | "type": "permanent", 50 | "civicAsPrimary": false, 51 | "schema": "dummy-20180201", 52 | "value": {} 53 | }, 54 | "leaves": [ 55 | { 56 | "identifier": "claim-cvc:Contact.email-v1", 57 | "value": "urn:email.domain.name:d8ca1591c2526a1b03e8ab9be02f32036c112b1b347e3cd7ae6bf5079ab249a2:X6gQFO3QYg|urn:email.domain.tld:58f18dc6fe5a24b3626fbd9a03548864dc380114a17f346f0d97d3b9cb0700d5:PSsiuGIgez|urn:email.username:3e19732ba77e798b6b85f55e3d5321e58108c758b865614a60b3198fb10c0d69:b6J7B5pCWo|", 58 | "claimPath": "contact.email", 59 | "targetHash": "1952a3a7260b286d1251f40db511d9b5cf78960a414791c96ac6437b2968a190", 60 | "node": [ 61 | { 62 | "right": "5478af59d9d5633434dbcac0c4d98d65c3c23dd80fb008081aabd5c95ea40642" 63 | }, 64 | { 65 | "right": "070c1ad44f28450390cd89e482bc4b8af8a41b4b1a5e112d9218bea051f6ad26" 66 | }, 67 | { 68 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 69 | }, 70 | { 71 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 72 | }, 73 | { 74 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 75 | } 76 | ] 77 | }, 78 | { 79 | "identifier": "claim-cvc:Email.domain-v1", 80 | "value": "urn:domain.name:d8ca1591c2526a1b03e8ab9be02f32036c112b1b347e3cd7ae6bf5079ab249a2:X6gQFO3QYg|urn:domain.tld:58f18dc6fe5a24b3626fbd9a03548864dc380114a17f346f0d97d3b9cb0700d5:PSsiuGIgez|", 81 | "claimPath": "contact.email.domain", 82 | "targetHash": "5478af59d9d5633434dbcac0c4d98d65c3c23dd80fb008081aabd5c95ea40642", 83 | "node": [ 84 | { 85 | "left": "1952a3a7260b286d1251f40db511d9b5cf78960a414791c96ac6437b2968a190" 86 | }, 87 | { 88 | "right": "070c1ad44f28450390cd89e482bc4b8af8a41b4b1a5e112d9218bea051f6ad26" 89 | }, 90 | { 91 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 92 | }, 93 | { 94 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 95 | }, 96 | { 97 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 98 | } 99 | ] 100 | }, 101 | { 102 | "identifier": "cvc:Meta:issuer", 103 | "value": "urn:issuer:572ac63d41247d7b2cb3f8f344447b51e1898e11206b38750261250f976fbedf:jest:test:fe07c3d0-e8b0-11e8-8a40-7fe4d191eb47|", 104 | "claimPath": "meta.issuer", 105 | "targetHash": "3e2858af4f6365227b60e562e6633c48f4c11665e0f80454a88591c71d3b1983", 106 | "node": [ 107 | { 108 | "right": "d20fab7ea0835b15ce3bc78118f0a044ce1f2da4fcaf06f2df465964811168b0" 109 | }, 110 | { 111 | "left": "f4688dcbf2bcd091b274227f1ffcd7a55a125526871caeda08b9ca344303fec6" 112 | }, 113 | { 114 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 115 | }, 116 | { 117 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 118 | }, 119 | { 120 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 121 | } 122 | ] 123 | }, 124 | { 125 | "identifier": "cvc:Meta:issuanceDate", 126 | "value": "urn:issuanceDate:34618d06738b071a224f2cf0236def1022dcfaf23827b85050cf653d27001635:2018-11-15T08:32:30.862Z|", 127 | "claimPath": "meta.issuanceDate", 128 | "targetHash": "d20fab7ea0835b15ce3bc78118f0a044ce1f2da4fcaf06f2df465964811168b0", 129 | "node": [ 130 | { 131 | "left": "3e2858af4f6365227b60e562e6633c48f4c11665e0f80454a88591c71d3b1983" 132 | }, 133 | { 134 | "left": "f4688dcbf2bcd091b274227f1ffcd7a55a125526871caeda08b9ca344303fec6" 135 | }, 136 | { 137 | "right": "b826226710e04f3cfbab3e877e574489a79c84ad3acffe651cd7e95cd3e6ac60" 138 | }, 139 | { 140 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 141 | }, 142 | { 143 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 144 | } 145 | ] 146 | }, 147 | { 148 | "identifier": "cvc:Meta:expirationDate", 149 | "value": "urn:expirationDate:629bc2bb479244a518ead46215278d86241cf206a4c32d5fff0eff3ef9f881ab:null|", 150 | "claimPath": "meta.expirationDate", 151 | "targetHash": "56eb2aa57e7d904e37bbe4cf4d9e34cd068ceeb1a18fd09d7be56bc9f715dfd0", 152 | "node": [ 153 | { 154 | "right": "856e21db11d11e74c7ca39b02adb7373283eaf205670b11a9dec9dc03f97c606" 155 | }, 156 | { 157 | "right": "740f2a0682cca1c44a1973a81fa24c3eaf81cb50f4effdcc7b1d76bc0f9da60c" 158 | }, 159 | { 160 | "left": "5cb4049edfe5a169032dbb4a66d01c59c64b50ef7d40ec2690d24429afd87ea4" 161 | }, 162 | { 163 | "right": "b0ce0c779bce746b589a4fca78d14dc482aa1e66bf015a15321644c0cceb4735" 164 | }, 165 | { 166 | "right": "322500cf2d9c6b3a1dc8a9c4cf9c0bfaddf244678395429f9f74806055224d81" 167 | } 168 | ] 169 | } 170 | ] 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /__test__/creds/proxyFixtures/PermanentAnchor.json: -------------------------------------------------------------------------------- 1 | { 2 | "subject": { 3 | "pub": "xpub:dummy", 4 | "label": "test1530668445601", 5 | "data": "test1530668445601", 6 | "signature": "304402204e4521f4f49baf55fb85539a2e8897e4fb05fad8bed6418e793d952ea63d559f02200f1a65d43392efe6e4388ced8694097333224685676e2c954c76efdbf87d4b55" 7 | }, 8 | "walletId": "5b3c25ae531deca003af947456de0316", 9 | "cosigners": [{ 10 | "pub": "xpub:dummy" 11 | }, { 12 | "pub": "xpub:dummy" 13 | }], 14 | "authority": { 15 | "pub": "xpub:dummy", 16 | "path": "/" 17 | }, 18 | "coin": "dummycoin", 19 | "tx": "d42108e60e941483045022100bd2fe1e1958424dddfac818c1cb9cf9b4b0758bff0165dafcb6ca3fb935864b80220621f79767d8b4a144f0b371ece12704eadc4d7cf60a23687d156fffdce9f76a3414c69522102896c0bad1cba92ff30e93a3301dcaed0c4a188e3a60e1b0abc64e572b38a70a12103f53ac90200000001ac0bacc5039e659e5a22365ca5f45f6f6f43b97c7d21812f457ca8a73122dcde00000000fdfd000047304402203cdac186e4678ce837b7acffbb769740fb440b419f237b407303858b3d29e4ed02204b62e3a5071bbca7c81581ced96d519b24d39114bedc13405fa81eac48ba895619b56825e473e7b5bb72a1c473a8f3bd0000000092bf025bf8da001210261d79a240feb1ba9642068856f928e3bd21985a443631007fed2fbed8d067c5353aeffffffff02db497d0f0000000017a914f7e370d5d2af95e058985724a4fe7c2c175f423087fb1700000000000017a914cd14854e02d273af9612ae649e7d13a2f73fcfde87", 20 | "network": "dummynet", 21 | "value": 259876034, 22 | "type": "permanent", 23 | "civicAsPrimary": false, 24 | "schema": "dummy-20180201" 25 | } -------------------------------------------------------------------------------- /__test__/creds/proxyFixtures/TempAnchor.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": "dummy-20180201", 3 | "tx": "01000000018815822815dbd6c355ad40da1f2fac328a408d538638143177168b57af5d753a00000000fc004730440220424268275da66825bc99a3f487472baa0751b67355407b4a4e99da04a3186c520220578b820dd051c919c2fb57b26aa29667483b547f6766a23e3c821e47a5d1237b0147304402201316cc0ee8a968f4d86a616fcf710b663e0bb7021e95d7a300036b65e95ca34602204f05162db06278af2a8abdd7ab4d92e973dc4154a92bf37a4056f3298fa9ecad014c695221028f9205846d9b23dd9a17588ae13603aa3eda3599582750904716c827d02269db210340f8f56a56b2af2a9698f66574882068cf8bd8fa95a26136ac34edabfe5eb5d021029d52d336232eb3d4f37730822df9d3993a84c3edba20f14d3ee0f20141c0bdfd53aeffffffff01551500000000000017a91460312cbbb8ec560305a239d56398f0d8aa57ecf68700000000", 4 | "subject": { 5 | "label": "teste", 6 | "pub": "xpub:dummy", 7 | "data": "testesdsd", 8 | "signature": "304502210089e94f11587bf7fa202817ace9664639855a146565d4e54b9f853f31f4d7ce31022077098a904e0dda7ab947db92a3e7dd7a5d52654c286151c3cc97feb0ef4a3310" 9 | }, 10 | "authority": { 11 | "pub": "xpub:dummy", 12 | "path": "/1/0/0/0" 13 | }, 14 | "cosigners": [{ 15 | "pub": "xpub:dummy" 16 | }, 17 | { 18 | "pub": "xpub:dummy" 19 | } 20 | ], 21 | "type": "temporary", 22 | "network": "dummynet" 23 | } -------------------------------------------------------------------------------- /__test__/creds/proxyFixtures/VCWithTamperedLeafValue.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "3636227c-5adf-4135-b81c-6dd1da53fd67", 3 | "issuer": "", 4 | "issuanceDate": "2018-11-13T18:54:11.665Z", 5 | "identifier": "credential-cvc:Email-v1", 6 | "expirationDate": null, 7 | "version": "1", 8 | "type": [ 9 | "Credential", 10 | "credential-cvc:Email-v1" 11 | ], 12 | "claim": { 13 | "contact": { 14 | "email": { 15 | "domain": { 16 | "name": "UTpHKFyaaB", 17 | "tld": "oVaPsceZ4C" 18 | }, 19 | "username": "ZcMpCBQ0lE" 20 | } 21 | } 22 | }, 23 | "proof": { 24 | "type": "CvcMerkleProof2018", 25 | "merkleRoot": "7f62f719275f47331782c57d98e138c2c063065476f73a38c99023ddf9009287", 26 | "anchor": "TBD (Civic Blockchain Attestation)", 27 | "leaves": [ 28 | { 29 | "identifier": "claim-cvc:Contact.email-v1", 30 | "value": "urn:email.domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaB|urn:email.domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|urn:email.username:705e41988a3659d943eeaaa5e6c91cc8de401674c4e130a7c44f5b4b2e8d7736:ZcMpCBQ0lE|", 31 | "claimPath": "contact.email", 32 | "targetHash": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7", 33 | "node": [ 34 | { 35 | "right": "e3662aeff5df76694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7" 36 | }, 37 | { 38 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 39 | }, 40 | { 41 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 42 | }, 43 | { 44 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 45 | }, 46 | { 47 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 48 | } 49 | ] 50 | }, 51 | { 52 | "identifier": "claim-cvc:Email.domain-v1", 53 | "value": "urn:domain.name:65572f78625ca98197745bd560fc5d8e6a7be7d8d9fcf6344947b697b73cd676:UTpHKFyaaB|urn:domain.tld:199c3b2cbc991cf024860f3cdfb71c956f0dea1fe397efb10ad1d8621163a9a1:oVaPsceZ4C|", 54 | "claimPath": "contact.email.domain", 55 | "targetHash": "e3662aeff5df76f0a694848bf529ec9e52f4a981d5a0afa27e48bfeae37992d7", 56 | "node": [ 57 | { 58 | "left": "dbd7c2e9f6369bdc1653cd29484b23324bac5cc2681bc956d5621163d10c82e7" 59 | }, 60 | { 61 | "right": "43a08a21a85219f2964a5473e270698296aeda22c08299ba61523d6b51bab102" 62 | }, 63 | { 64 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 65 | }, 66 | { 67 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 68 | }, 69 | { 70 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 71 | } 72 | ] 73 | }, 74 | { 75 | "identifier": "cvc:Meta:issuer", 76 | "value": "urn:issuer:3c1d9cc9f8bd5dd7f4845c18017c559ecee758c6dc2f5a3b63385bf3f681e13a:|", 77 | "claimPath": "meta.issuer", 78 | "targetHash": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b", 79 | "node": [ 80 | { 81 | "right": "2820718fc34e3e07c40c4c0c0985937a193a63839695768f38630acfbecaf85d" 82 | }, 83 | { 84 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 85 | }, 86 | { 87 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 88 | }, 89 | { 90 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 91 | }, 92 | { 93 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 94 | } 95 | ] 96 | }, 97 | { 98 | "identifier": "cvc:Meta:issuanceDate", 99 | "value": "urn:issuanceDate:0029acb02ff26faf7775883957e9a5271b358f56734496b7ffde2760ace9ddce:2018-11-13T18:54:11.665Z|", 100 | "claimPath": "meta.issuanceDate", 101 | "targetHash": "2820718fc34e3e07c40c4c0c098937a193a63839695768f38630acfbecaf85d", 102 | "node": [ 103 | { 104 | "left": "321c8608ee0b80eab76db4d753e1f5311e722d0d77468e376bc25a78b8560b1b" 105 | }, 106 | { 107 | "left": "b13aa2fb81649ae46142393ef503c7dea123f60e0909002f9f5d19a49cf8c787" 108 | }, 109 | { 110 | "right": "825986e22e786f431106b7e262bda5a2b8d7794a5ad6158727d77c978b47d290" 111 | }, 112 | { 113 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 114 | }, 115 | { 116 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 117 | } 118 | ] 119 | }, 120 | { 121 | "identifier": "cvc:Meta:expirationDate", 122 | "value": "urn:expirationDate:f437c1d530d5422b3df947b7d97da82c5abfee582c1be15bd2900ff35e8d0624:null|", 123 | "claimPath": "meta.expirationDate", 124 | "targetHash": "c73ce4be4e264f366dfc8a95abf7e507e75d13a2a06af5e50d2dc09e6c71d9cd", 125 | "node": [ 126 | { 127 | "right": "8c741ed5a929697f02cfb47019d1e60ed038ac40b4f32ef52ae48ea0fa93c0fe" 128 | }, 129 | { 130 | "right": "9740db43522f2170c4ad18230f53ac4dbdb9f7e423687e320767b569d6ee12be" 131 | }, 132 | { 133 | "left": "63866d32feddce9393a91d54b85d370c5cfc38641ce3b4db2df73499b9347918" 134 | }, 135 | { 136 | "right": "15442a3233e960fb6165bad383a9e7eca948a70576e42c627c1d71ca4bf15644" 137 | }, 138 | { 139 | "right": "81c3ed3f0c3da91e4d8d8d0143c2ef10ee92f911d5f1c941d67c8545f251d5d4" 140 | } 141 | ] 142 | } 143 | ] 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /__test__/creds/proxyFixtures/filteredIdDocument-v2.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "f471b5f8-6ad6-4782-968d-f2924145fa54", 3 | "issuer": "", 4 | "issuanceDate": "2021-05-26T20:11:12.082Z", 5 | "identifier": "credential-cvc:IdDocument-v2", 6 | "expirationDate": null, 7 | "version": "1", 8 | "type": [ 9 | "Credential", 10 | "credential-cvc:IdDocument-v2" 11 | ], 12 | "transient": false, 13 | "claim": { 14 | "document": { 15 | "dateOfBirth": { 16 | "day": 20, 17 | "month": 3, 18 | "year": 1978 19 | } 20 | } 21 | }, 22 | "proof": { 23 | "type": "CvcMerkleProof2018", 24 | "merkleRoot": "9d424cbc30d418ed42f1b1031fa4fdef273e6b371637b4c8e5184a566b9d27cc", 25 | "anchor": "TBD (Civic Blockchain Attestation)", 26 | "leaves": [ 27 | { 28 | "identifier": "claim-cvc:Document.dateOfBirth-v1", 29 | "value": "urn:dateOfBirth.day:f0bbfa2a35fc0dfa27a2620691feedde6fff1c522817b546e730740f7339354d:20|urn:dateOfBirth.month:75e6e5fa1f03d6b985862e7ad1467405e0c482df64e6ed1692312aaba7d4d951:3|urn:dateOfBirth.year:c4d7200e945ef41009be24127cdd394d17a7bc0330d3b1b19270372543ff6517:1978|", 30 | "claimPath": "document.dateOfBirth", 31 | "targetHash": "3fdb18a8022d009da8eda7b353ebfdaad91ad4d6256f647e174ac16448d42f6d", 32 | "node": [ 33 | { 34 | "left": "72e6f2e8c817048bb82442371202c9c078cabbacb7739ce4781f68855b362ca8" 35 | }, 36 | { 37 | "right": "aae76d0dd2b272496a4ccc799cd60a329da4d78742b9e4f8792c4a3b4259d414" 38 | }, 39 | { 40 | "right": "9c4a9d7c1d1a76dd3c8aa274d6cf8de8cd5ed4658162c84db409e8c0dab422ea" 41 | }, 42 | { 43 | "left": "03024ff54437b7d65ad908229977e8603f3f5451a611ec88235775db23d522f5" 44 | }, 45 | { 46 | "right": "b8dc070cacd5d604ec328cfee7d396e3a6ba5011a616049126d37460f7280154" 47 | } 48 | ] 49 | } 50 | ] 51 | }, 52 | "granted": null 53 | } -------------------------------------------------------------------------------- /__test__/errors/idvErrors.test.js: -------------------------------------------------------------------------------- 1 | const { IDVErrorCodes } = require('../../src/errors/idvErrors'); 2 | 3 | describe('IDV Errors', () => { 4 | it('Should have IDV Error Codes', () => { 5 | expect(IDVErrorCodes).toHaveProperty('ERROR_IDV_UCA_MISSING_PROPERTY'); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /__test__/index.test.js: -------------------------------------------------------------------------------- 1 | const CredentialCommons = require('../src/index'); 2 | const httpMock = require('../src/services/__mocks__/httpService'); 3 | 4 | const { Claim, VC } = CredentialCommons; 5 | 6 | describe('Module Entry Point Tests', () => { 7 | it('should access the entry point e see if the modules are declared', () => { 8 | const confMock = { 9 | sipSecurityService: '', 10 | attestationService: '', 11 | clientConfig: { 12 | id: '', 13 | signingKeys: { 14 | hexpub: '', 15 | hexsec: '', 16 | }, 17 | }, 18 | passphrase: '', 19 | keychain: { prv: '' }, 20 | }; 21 | CredentialCommons.init(confMock, httpMock); 22 | expect(Claim).toBeDefined(); 23 | expect(VC).toBeDefined(); 24 | }); 25 | 26 | it('Should initialize with custom SecureRandom', () => { 27 | const confMock = { 28 | sipSecurityService: '', 29 | attestationService: '', 30 | clientConfig: { 31 | id: '', 32 | signingKeys: { 33 | hexpub: '', 34 | hexsec: '', 35 | }, 36 | }, 37 | passphrase: '', 38 | keychain: { prv: '' }, 39 | }; 40 | 41 | const myCustomSecureRandom = function MyCustomSecureRandom() {}; 42 | 43 | CredentialCommons.init(confMock, httpMock, myCustomSecureRandom); 44 | expect(Claim).toBeDefined(); 45 | expect(VC).toBeDefined(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /__test__/isClaimRelated.test.js: -------------------------------------------------------------------------------- 1 | const isClaimRelated = require('../src/isClaimRelated'); 2 | const { schemaLoader, CVCSchemaLoader } = require('../src'); 3 | 4 | jest.setTimeout(30000); 5 | 6 | describe('isClaimRelated Tests', () => { 7 | beforeAll(() => { 8 | schemaLoader.addLoader(new CVCSchemaLoader()); 9 | }); 10 | 11 | beforeEach(() => { 12 | schemaLoader.reset(); 13 | }); 14 | 15 | it('Should validate a claim path against UCA definitions ' 16 | + 'and VC definitions and succeed', async (done) => { 17 | const uca = 'claim-claim-cvc:Document.name-v1-1'; 18 | const claim = 'document.name.givenNames'; 19 | const credential = 'credential-cvc:GenericDocumentId-v1'; 20 | const validation = await isClaimRelated(claim, uca, credential); 21 | expect(validation).toBeTruthy(); 22 | done(); 23 | }); 24 | 25 | it('Should validate a claim path against UCA definitions and VC definitions and ' 26 | + 'succeed returning false for an non existent dependency', async (done) => { 27 | const uca = 'claim-claim-cvc:Contact.phoneNumber-v1-1'; 28 | const claim = 'contact.phoneNumber.number'; 29 | const credential = 'credential-cvc:GenericDocumentId-v1'; 30 | const validation = await isClaimRelated(claim, uca, credential); 31 | expect(validation).toBeFalsy(); 32 | done(); 33 | }); 34 | 35 | it('Should fail validation of a wrong defined uca global identifier', () => expect(isClaimRelated( 36 | 'document.name.givenNames', 'claim-civ:Identity:error-1', 'credential-cvc:GenericDocumentId-v1', 37 | )).rejects.toThrow(/UCA identifier does not exist/)); 38 | 39 | 40 | it('Should fail validation of a wrong defined claim path identifier', () => expect(isClaimRelated( 41 | 'name.error', 'claim-claim-cvc:Document.name-v1-1', 'credential-cvc:GenericDocumentId-v1', 42 | )).rejects.toThrow(/Claim property path does not exist on UCA definitions/)); 43 | 44 | it('Should fail validation of a wrong defined credential parent identifier', 45 | () => expect(isClaimRelated( 46 | 'document.name.givenNames', 'claim-claim-cvc:Document.name-v1-1', 'civ:Credential:Generic', 47 | )).rejects.toThrow(/Credential identifier does not exist/)); 48 | }); 49 | -------------------------------------------------------------------------------- /__test__/isValidGlobalIdentifier.test.js: -------------------------------------------------------------------------------- 1 | const isGlobalIdentifier = require('../src/isValidGlobalIdentifier'); 2 | const { schemaLoader, CVCSchemaLoader } = require('../src'); 3 | 4 | 5 | describe('isGlobalIdentifier Tests', () => { 6 | beforeAll(() => { 7 | schemaLoader.addLoader(new CVCSchemaLoader()); 8 | }); 9 | 10 | beforeEach(() => { 11 | schemaLoader.reset(); 12 | }); 13 | 14 | test('name-v1 is malformed', () => expect(isGlobalIdentifier('name-v1')) 15 | .rejects.toThrow(/Malformed Global Identifier/)); 16 | 17 | test('credentialItem-civ:Identity:firstName-1 has invalid prefix', 18 | () => expect(isGlobalIdentifier('credentialItem-civ:Identity:firstName-1')) 19 | .rejects.toThrow(/Invalid Global Identifier Prefix/)); 20 | 21 | test('claim-civ:Identity:firstNome-1 is invalid', 22 | () => expect(isGlobalIdentifier('claim-civ:Identity:firstNome-1')) 23 | .rejects.toThrow(/claim-civ:Identity:firstNome-1 is not valid/)); 24 | 25 | test('credential-civ:Credential:CivicBasico-1 is invalid', 26 | () => expect(isGlobalIdentifier('credential-civ:Credential:CivicBasico-1')) 27 | .rejects.toThrow(/credential-civ:Credential:CivicBasico-1 is not valid/)); 28 | 29 | test('claim-cvc:Name.givenNames-v1 is valid', async () => { 30 | expect(await isGlobalIdentifier('claim-cvc:Name.givenNames-v1')).toBeTruthy(); 31 | }); 32 | 33 | test('credential-cvc:Identity-v1 is valid', async () => { 34 | expect(await isGlobalIdentifier('credential-cvc:Identity-v1')).toBeTruthy(); 35 | }); 36 | 37 | test('credential-cvc:IDVaaS-v1 is valid', async () => { 38 | expect(await isGlobalIdentifier('credential-cvc:IDVaaS-v1')).toBeTruthy(); 39 | }); 40 | 41 | test('credential-cvc:IdDocument-v1 is valid', async () => { 42 | expect(await isGlobalIdentifier('credential-cvc:IdDocument-v1')).toBeTruthy(); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /__test__/lib/did.test.js: -------------------------------------------------------------------------------- 1 | const { 2 | mockDids, 3 | DID_WITH_NO_DEFAULT, 4 | DID_SPARSE, 5 | DID_CONTROLLER, 6 | DID_CONTROLLED, 7 | } = require('./util/did'); 8 | const didUtil = require('../../src/lib/did'); 9 | 10 | describe('DIDs', () => { 11 | beforeAll(mockDids); 12 | 13 | it('resolves a did:sol document', async () => { 14 | const document = await didUtil.resolve(DID_SPARSE); 15 | 16 | expect(document).toBeTruthy(); 17 | expect(document.id).toBe(DID_SPARSE); 18 | }); 19 | 20 | it('finds a valid verification method on a DID document', async () => { 21 | const vm = `${DID_SPARSE}#default`; 22 | const document = await didUtil.resolve(DID_SPARSE); 23 | const verificationMethod = didUtil.findVerificationMethod(document, vm); 24 | 25 | expect(verificationMethod).toBeTruthy(); 26 | expect(verificationMethod.id).toBe(vm); 27 | expect(verificationMethod.controller).toBe(DID_SPARSE); 28 | }); 29 | 30 | it('doesn\'t find a verification that is not valid on the document', async () => { 31 | const vm = `${DID_WITH_NO_DEFAULT}#default`; 32 | const document = await didUtil.resolve(DID_WITH_NO_DEFAULT); 33 | const verificationMethod = didUtil.findVerificationMethod(document, vm); 34 | 35 | expect(verificationMethod).toBe(null); 36 | }); 37 | 38 | it('verificationMethod can sign for a DID', async () => { 39 | const canSign = await didUtil.canSign(DID_SPARSE, `${DID_SPARSE}#default`); 40 | 41 | expect(canSign).toBeTruthy(); 42 | }); 43 | 44 | it('verificationMethod can not sign for a DID if the key does not exist', async () => { 45 | const canSign = await didUtil.canSign(DID_SPARSE, `${DID_SPARSE}#key2`); 46 | 47 | expect(canSign).toBeFalsy(); 48 | }); 49 | 50 | it('verificationMethod can not sign for a DID where the default key is removed', async () => { 51 | const canSign = await didUtil.canSign(DID_WITH_NO_DEFAULT, `${DID_WITH_NO_DEFAULT}#default`); 52 | 53 | expect(canSign).toBeFalsy(); 54 | }); 55 | 56 | it('verificationMethod can sign for a DID it is a controller of', async () => { 57 | const canSign = await didUtil.canSign(DID_CONTROLLED, `${DID_CONTROLLER}#default`); 58 | 59 | expect(canSign).toBeTruthy(); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /__test__/lib/fixtures/sol.did.controlled.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/did/v1.0", 4 | "https://w3id.org/sol/v1" 5 | ], 6 | "id": "did:sol:localnet:2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD", 7 | "controller": [ 8 | "did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9" 9 | ], 10 | "verificationMethod": [ 11 | { 12 | "id": "did:sol:localnet:2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD#default", 13 | "type": "Ed25519VerificationKey2018", 14 | "controller": "did:sol:localnet:2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD", 15 | "publicKeyBase58": "2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD" 16 | } 17 | ], 18 | "authentication": [], 19 | "assertionMethod": [], 20 | "keyAgreement": [], 21 | "capabilityInvocation": [ 22 | "did:sol:localnet:2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD#default" 23 | ], 24 | "capabilityDelegation": [], 25 | "service": [], 26 | "publicKey": [ 27 | { 28 | "id": "did:sol:localnet:2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD#default", 29 | "type": "Ed25519VerificationKey2018", 30 | "controller": "did:sol:localnet:2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD", 31 | "publicKeyBase58": "2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /__test__/lib/fixtures/sol.did.controller.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/did/v1.0", 4 | "https://w3id.org/sol/v1" 5 | ], 6 | "id": "did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9", 7 | "controller": [], 8 | "verificationMethod": [ 9 | { 10 | "id": "did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9#default", 11 | "type": "Ed25519VerificationKey2018", 12 | "controller": "did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9", 13 | "publicKeyBase58": "DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9" 14 | } 15 | ], 16 | "authentication": [], 17 | "assertionMethod": [], 18 | "keyAgreement": [], 19 | "capabilityInvocation": [ 20 | "did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9#default" 21 | ], 22 | "capabilityDelegation": [], 23 | "service": [], 24 | "publicKey": [ 25 | { 26 | "id": "did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9#default", 27 | "type": "Ed25519VerificationKey2018", 28 | "controller": "did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9", 29 | "publicKeyBase58": "DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /__test__/lib/fixtures/sol.did.no_default_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/did/v1.0", 4 | "https://w3id.org/sol/v1" 5 | ], 6 | "id": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT", 7 | "controller": [], 8 | "verificationMethod": [ 9 | { 10 | "id": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT#default", 11 | "type": "Ed25519VerificationKey2018", 12 | "controller": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT", 13 | "publicKeyBase58": "DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT" 14 | }, 15 | { 16 | "id": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT#mobile", 17 | "type": "Ed25519VerificationKey2018", 18 | "controller": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT", 19 | "publicKeyBase58": "DD6a2ZkggrMfsmBS5UzYA8aTx9D1C99dyokHhptepinz" 20 | } 21 | ], 22 | "authentication": [], 23 | "assertionMethod": [], 24 | "keyAgreement": [], 25 | "capabilityInvocation": [ 26 | "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT#mobile" 27 | ], 28 | "capabilityDelegation": [], 29 | "service": [], 30 | "publicKey": [ 31 | { 32 | "id": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT#default", 33 | "type": "Ed25519VerificationKey2018", 34 | "controller": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT", 35 | "publicKeyBase58": "DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT" 36 | }, 37 | { 38 | "id": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT#mobile", 39 | "type": "Ed25519VerificationKey2018", 40 | "controller": "did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT", 41 | "publicKeyBase58": "DD6a2ZkggrMfsmBS5UzYA8aTx9D1C99dyokHhptepinz" 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /__test__/lib/fixtures/sol.did.sparse.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/did/v1.0", 4 | "https://w3id.org/sol/v1" 5 | ], 6 | "id": "did:sol:localnet:6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf", 7 | "controller": [], 8 | "verificationMethod": [ 9 | { 10 | "id": "did:sol:localnet:6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf#default", 11 | "type": "Ed25519VerificationKey2018", 12 | "controller": "did:sol:localnet:6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf", 13 | "publicKeyBase58": "6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf" 14 | } 15 | ], 16 | "authentication": [], 17 | "assertionMethod": [], 18 | "keyAgreement": [], 19 | "capabilityInvocation": [ 20 | "did:sol:localnet:6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf#default" 21 | ], 22 | "capabilityDelegation": [], 23 | "service": [], 24 | "publicKey": [ 25 | { 26 | "id": "did:sol:localnet:6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf#default", 27 | "type": "Ed25519VerificationKey2018", 28 | "controller": "did:sol:localnet:6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf", 29 | "publicKeyBase58": "6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /__test__/lib/signerVerifier.test.js: -------------------------------------------------------------------------------- 1 | const nacl = require('tweetnacl'); 2 | const signerVerifier = require('../../src/lib/signerVerifier'); 3 | const { 4 | mockDids, 5 | DID_SPARSE, 6 | privateKeyBase58, 7 | keyPair, 8 | } = require('./util/did'); 9 | 10 | const DUMMY_MERKLE_ROOT = 'aa4149dda8fd2fac435898372f1de399140f6c50dbc3d40585c913701ce902c4'; 11 | 12 | describe('signerVerifier', () => { 13 | beforeAll(mockDids); 14 | 15 | it('creates a signer from a private key', async () => { 16 | const privateKey = privateKeyBase58(DID_SPARSE); 17 | const verificationMethod = `${DID_SPARSE}#default`; 18 | 19 | const signer = await signerVerifier.signer({ 20 | verificationMethod, 21 | privateKey, 22 | }); 23 | 24 | const signed = signer.sign({ merkleRoot: DUMMY_MERKLE_ROOT }); 25 | 26 | expect(signed).toBeTruthy(); 27 | 28 | const verifier = await signerVerifier.verifier(DID_SPARSE, verificationMethod); 29 | const verified = verifier.verify({ 30 | issuer: DID_SPARSE, 31 | proof: { 32 | merkleRoot: DUMMY_MERKLE_ROOT, 33 | merkleRootSignature: signed, 34 | }, 35 | }); 36 | 37 | expect(verified).toBe(true); 38 | }); 39 | 40 | it('creates a signer from a keypair', async () => { 41 | const keypair = keyPair(DID_SPARSE); 42 | const verificationMethod = `${DID_SPARSE}#default`; 43 | 44 | const signer = await signerVerifier.signer({ 45 | verificationMethod, 46 | keypair, 47 | }); 48 | 49 | const signed = signer.sign({ merkleRoot: DUMMY_MERKLE_ROOT }); 50 | 51 | expect(signed).toBeTruthy(); 52 | 53 | const verifier = await signerVerifier.verifier(DID_SPARSE, verificationMethod); 54 | const verified = verifier.verify({ 55 | issuer: DID_SPARSE, 56 | proof: { 57 | merkleRoot: DUMMY_MERKLE_ROOT, 58 | merkleRootSignature: signed, 59 | }, 60 | }); 61 | 62 | expect(verified).toBe(true); 63 | }); 64 | 65 | it('uses a provided signer', async () => { 66 | const verificationMethod = `${DID_SPARSE}#default`; 67 | const keypair = keyPair(DID_SPARSE); 68 | 69 | const customSigner = { 70 | sign(proof) { 71 | const encodedData = Buffer.from(proof.merkleRoot, 'hex'); 72 | 73 | const signature = nacl.sign.detached(encodedData, keypair.secretKey); 74 | 75 | return { 76 | signature, 77 | verificationMethod, 78 | }; 79 | }, 80 | }; 81 | 82 | const signer = await signerVerifier.signer({ 83 | verificationMethod, 84 | signer: customSigner, 85 | }); 86 | 87 | const signed = signer.sign({ merkleRoot: DUMMY_MERKLE_ROOT }); 88 | 89 | expect(signed).toBeTruthy(); 90 | 91 | const verifier = await signerVerifier.verifier(DID_SPARSE, verificationMethod); 92 | const verified = verifier.verify({ 93 | issuer: DID_SPARSE, 94 | proof: { 95 | merkleRoot: DUMMY_MERKLE_ROOT, 96 | merkleRootSignature: signed, 97 | }, 98 | }); 99 | 100 | expect(verified).toBe(true); 101 | }); 102 | }); 103 | -------------------------------------------------------------------------------- /__test__/lib/util/did.js: -------------------------------------------------------------------------------- 1 | const nacl = require('tweetnacl'); 2 | const bs58 = require('bs58'); 3 | const didUtil = require('../../../src/lib/did'); 4 | 5 | // A default sparse DID document 6 | const DID_SPARSE = 'did:sol:localnet:6ffRJDKb3Ve83A9SsJmjyYk5Ef3LXcRkZAT6hXhBBrHf'; 7 | // A DID document where the default key has been removed 8 | const DID_WITH_NO_DEFAULT = 'did:sol:localnet:DwZYFeU2fy8JpmxwL8gH3CVqKcbeb2MALyEf1tVyyDAT'; 9 | // A controller DID (to be used with DID_CONTROLLED) 10 | const DID_CONTROLLER = 'did:sol:localnet:DY5HzWG9GJGTw3cfkFndMapGGMXpPVBhRe9jEJjX25u9'; 11 | // A controlled DID (to be used with DID_CONTROLLER) 12 | const DID_CONTROLLED = 'did:sol:localnet:2McEWrgSX2oU3aEWkJrpGN49kDp3ciKrH5MTi8vvuZpD'; 13 | 14 | // Holds reference and PK for DID document fixtures 15 | const DOCUMENTS = {}; 16 | DOCUMENTS[DID_WITH_NO_DEFAULT] = [ 17 | 'sol.did.no_default_key.json', 18 | '67R6neGjm4L9kdJ4LbqLmgT3UecoHKwSBXh4zQUVRy4HqzxUFBR1uGCHxGoMbr98ACuT9XtKZejfUMvqQdDepUyq', 19 | ]; 20 | DOCUMENTS[DID_SPARSE] = [ 21 | 'sol.did.sparse.json', 22 | '2yvWghJhJvMY3LLqpwdb3dCoKJiEm2s7TLLHgVKU81bgTnPdqKgSMzvR2qePG9cmGHJkpnwQTyPXTwFzpJ9JSMfw', 23 | ]; 24 | DOCUMENTS[DID_CONTROLLER] = [ 25 | 'sol.did.controller.json', 26 | 'GQqLfmWSkTazpXjDgRGAvVVPqpb4LWjFFsVVBBZ5cMtJQEu47YrG7uyCMsVRequfJ2xrSohzJhKbeC56ivXfn79', 27 | ]; 28 | DOCUMENTS[DID_CONTROLLED] = [ 29 | 'sol.did.controlled.json', 30 | '4shZPR61QMm4mCyS9EDMmKtPN7K4pZfysKXZ5YX7QDoHFRrHXmU7pECq7VxeQgGm8ih6jrVjynHy6EJx7b5MfZZK', 31 | ]; 32 | 33 | // mocks didUtil.resolve to return local fixtures instead of looking it up 34 | const mockDids = () => { 35 | didUtil.resolve = jest.fn() 36 | .mockImplementation((did) => { 37 | if (!DOCUMENTS[did]) { 38 | return null; 39 | } 40 | 41 | // eslint-disable-next-line global-require,import/no-dynamic-require 42 | return require(`../fixtures/${DOCUMENTS[did][0]}`); 43 | }) 44 | .bind(didUtil); 45 | 46 | return didUtil; 47 | }; 48 | 49 | /** 50 | * Returns a keyPair for one of the above DIDs 51 | * @param did 52 | * @returns {nacl.SignKeyPair} 53 | */ 54 | const keyPair = (did) => { 55 | const pk = DOCUMENTS[did][1]; 56 | 57 | return nacl.sign.keyPair.fromSecretKey(bs58.decode(pk)); 58 | }; 59 | 60 | /** 61 | * Returns the base58 encoded private key for one of the above DIDs 62 | */ 63 | const privateKeyBase58 = did => DOCUMENTS[did][1]; 64 | 65 | module.exports = { 66 | DID_WITH_NO_DEFAULT, 67 | DID_CONTROLLER, 68 | DID_CONTROLLED, 69 | DID_SPARSE, 70 | mockDids, 71 | keyPair, 72 | privateKeyBase58, 73 | }; 74 | -------------------------------------------------------------------------------- /__test__/schema/fixtures/credential-test:IdDocument-v1.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "http://identity.com/schemas/credential-test:IdDocument-v1", 4 | "title": "credential-test:IdDocument-v1", 5 | "type": "object", 6 | "allOf": [ 7 | { 8 | "$ref": "http://identity.com/schemas/credential-cvc:IdDocument-v3" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /__test__/services/AggregationService.test.js: -------------------------------------------------------------------------------- 1 | const aggregate = require('../../src/AggregationHandler'); 2 | 3 | describe('Aggregation Service', () => { 4 | it('should throw Invalid Operator', () => { 5 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 6 | expect(() => { 7 | aggregate(collection, [{ $toString: null }]); 8 | }).toThrow('Invalid operator: $toString'); 9 | }); 10 | 11 | it('should return a collection with same equality', () => { 12 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 13 | const result = aggregate(collection, [{ none: null }]); 14 | expect(result).toStrictEqual(collection); 15 | }); 16 | 17 | it('should return the first 2 elements only', () => { 18 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 19 | const result = aggregate(collection, [{ $limit: 2 }]); 20 | expect(result).toStrictEqual([{ k: 'a' }, { k: 'b' }]); 21 | }); 22 | 23 | it('should return the first elements only', () => { 24 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 25 | const result = aggregate(collection, [{ $first: 'true' }]); 26 | expect(result).toStrictEqual([{ k: 'a' }]); 27 | }); 28 | 29 | it('should return the first elements using boolean', () => { 30 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 31 | const result = aggregate(collection, [{ $first: true }]); 32 | expect(result).toStrictEqual([{ k: 'a' }]); 33 | }); 34 | 35 | it('should return the last elements only', () => { 36 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 37 | const result = aggregate(collection, [{ $last: 'true' }]); 38 | expect(result).toStrictEqual([{ k: 'c' }]); 39 | }); 40 | 41 | it('should return the last elements using boolean', () => { 42 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 43 | const result = aggregate(collection, [{ $last: true }]); 44 | expect(result).toStrictEqual([{ k: 'c' }]); 45 | }); 46 | 47 | it('should return the max elements only', () => { 48 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 49 | const result = aggregate(collection, [{ $max: 'k' }]); 50 | expect(result).toStrictEqual([{ k: 'c' }]); 51 | }); 52 | 53 | it('should return the min elements only', () => { 54 | const collection = [{ k: 'a' }, { k: 'b' }, { k: 'c' }]; 55 | const result = aggregate(collection, [{ $min: 'k' }]); 56 | expect(result).toStrictEqual([{ k: 'a' }]); 57 | }); 58 | 59 | it('should return in ascending order ', () => { 60 | const collection = [{ k: 'b' }, { k: 'a' }, { k: 'c' }]; 61 | const result = aggregate(collection, [{ $sort: { k: 'ASC' } }]); 62 | expect(result).toStrictEqual([{ k: 'a' }, { k: 'b' }, { k: 'c' }]); 63 | }); 64 | 65 | it('should return in descending order ', () => { 66 | const collection = [{ k: 'b' }, { k: 'a' }, { k: 'c' }]; 67 | const result = aggregate(collection, [{ $sort: { k: 'DES' } }]); 68 | expect(result).toStrictEqual([{ k: 'c' }, { k: 'b' }, { k: 'a' }]); 69 | }); 70 | 71 | it('should apply operations in order', () => { 72 | const collection = [{ k: 'b' }, { k: 'a' }, { k: 'c' }]; 73 | const result = aggregate(collection, [ 74 | { $sort: { k: 'DES' } }, 75 | { $limit: 2 }]); 76 | expect(result).toStrictEqual([{ k: 'c' }, { k: 'b' }]); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /__test__/services/MiniCryptoManagerImpl.test.js: -------------------------------------------------------------------------------- 1 | const sjcl = require('sjcl'); 2 | const MiniCryptoManagerImpl = require('../../src/services/MiniCryptoManagerImpl'); 3 | 4 | const XPVT = 'xprvA1yULd2DFYnQRVbLiAKrFdftVLsANiC3rqLvp8iiCbnchcWqd6kJPoaV3sy7R6CjHM8RbpoNdWVgiPZLVa1EmneRLtwiitNpWgwyVmjvay7'; // eslint-disable-line 5 | const XPUB = 'xpub6Expk8Z75vLhdyfopBrrcmcd3NhenAuuE4GXcX8KkwKbaQqzAe4Ywbtxu9F95hRHj79PvdtYEJcoR6gesbZ79fS4bLi1PQtm81rjxAHeLL9'; // eslint-disable-line 6 | 7 | describe('Unit tests for MiniCryptoManager', () => { 8 | let cryptoManagerImpl; 9 | 10 | beforeAll(async (done) => { 11 | cryptoManagerImpl = new MiniCryptoManagerImpl(); 12 | done(); 13 | }); 14 | 15 | test('Should sign with XPVT key and verify with XPUB pair', async (done) => { 16 | const nonce = new Date().getTime(); 17 | const stringWithNonce = `SomeStringWithNonce${nonce}`; 18 | const hexHashNonce = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(stringWithNonce)); 19 | 20 | const keyNameSign = 'KeyNameToSign'; 21 | cryptoManagerImpl.installKey(keyNameSign, XPVT); 22 | 23 | const hexSignature = cryptoManagerImpl.sign(keyNameSign, hexHashNonce); 24 | expect(hexSignature).toBeDefined(); 25 | 26 | const stringWithNonceToVerify = `SomeStringWithNonce${nonce}`; 27 | const hexHashNonceToVerify = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(stringWithNonceToVerify)); 28 | 29 | const keyNameVerify = 'KeyNameToVerify'; 30 | cryptoManagerImpl.installKey(keyNameVerify, XPUB); 31 | 32 | const verify = cryptoManagerImpl.verify(keyNameVerify, hexHashNonceToVerify, hexSignature); 33 | expect(verify).toEqual(true); 34 | done(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /__test__/services/config.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | describe('Config tests', () => { 4 | it('Should validate that it\'s not a node environment', () => { 5 | const processEnvNodeBefore = process.env.NODE_ENV; 6 | process.env.APP_ENV = 'browser'; 7 | // there is no other way to bypass a require process.env 8 | // eslint-disable-next-line no-trailing-spaces,global-require 9 | const config = require('../../src/services/config'); 10 | expect(config).toBeDefined(); 11 | process.env.NODE_ENV = processEnvNodeBefore; 12 | }); 13 | 14 | it('Should force an non existent config file', () => { 15 | fs.existsSync = jest.fn(() => null); 16 | // eslint-disable-next-line no-trailing-spaces,global-require 17 | const config = require('../../src/services/config'); 18 | expect(config).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /__test__/services/configBranch.test.js: -------------------------------------------------------------------------------- 1 | // do not put these tests on the same file as config.test.js or else jest will fail coverage 2 | // (describe.beforeEach scope not working) 3 | 4 | // the original platform is stored to temporarily stub win32 platform to test failing in the tests temporarily 5 | const originalPlatform = process.platform; 6 | 7 | describe('Test process platform', () => { 8 | beforeEach(() => { 9 | Object.defineProperty(process, 'platform', { 10 | value: 'win32', 11 | }); 12 | }); 13 | 14 | it('Should validate that it is in windows', () => { 15 | // it's not linting because we need to test branching of this config file 16 | try { 17 | // eslint-disable-next-line no-trailing-spaces,global-require 18 | require('../../src/services/config'); 19 | } catch (err) { 20 | expect(err.message).toBe('Unsupported platform: win32'); 21 | } 22 | }); 23 | 24 | afterEach(() => { 25 | Object.defineProperty(process, 'platform', { 26 | value: originalPlatform, 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /__test__/services/services.test.js: -------------------------------------------------------------------------------- 1 | const { services, initServices } = require('../../src/services/index'); 2 | const httpMock = require('../../src/services/__mocks__/httpService'); 3 | 4 | describe('Services Container Tests', () => { 5 | test('Has HTTP Service', () => { 6 | const http = services.container.Http; 7 | expect(http).toBeDefined(); 8 | }); 9 | test('Has Anchor Service', () => { 10 | const anchorService = services.container.AnchorService; 11 | expect(anchorService).toBeDefined(); 12 | }); 13 | test('Has Config Service', () => { 14 | const config = services.container.Config; 15 | expect(config).toBeDefined(); 16 | }); 17 | test('Override HTTP Service', () => { 18 | expect(httpMock).toBeDefined(); 19 | initServices(null, httpMock); 20 | const http = services.container.Http; 21 | expect(http).toBeDefined(); 22 | expect(http.name).toBe('mockHttp'); 23 | }); 24 | test('Override Config Service', () => { 25 | initServices({ test: '' }, null); 26 | const http = services.container.Http; 27 | expect(http).toBeDefined(); 28 | // TODO cannot branch out the IFs to cover all code this is strange 29 | expect(http.name).toBe('mockHttp'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /audit-ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "low": true, 3 | "package-manager": "auto", 4 | "report": true, 5 | "allowlist": [1086436, 1088664, 1088730, 1088811, 1088828, 1088831, 1088948, 1089128, 1089129, 1089152, 1089185, 1089394, 1089513, 1090135, 1090146, 1090169, 1090170, 1090532] 6 | } 7 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | cjs: { 4 | presets: [ 5 | ['@babel/preset-env', { 6 | targets: { 7 | node: '6.10', 8 | }, 9 | modules: 'commonjs', 10 | }], 11 | ], 12 | }, 13 | browser: { 14 | presets: [ 15 | [ 16 | '@babel/preset-env', 17 | { 18 | targets: { 19 | browsers: ['last 2 versions'], 20 | }, 21 | shippedProposals: true, 22 | }, 23 | ], 24 | ], 25 | plugins: ['@babel/plugin-transform-runtime'], 26 | }, 27 | test: { 28 | plugins: ['@babel/plugin-transform-modules-commonjs'], 29 | }, 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@identity.com/credential-commons", 3 | "version": "3.0.2", 4 | "author": "Identity.com Community", 5 | "license": "MIT", 6 | "description": "Verifiable Credential and Attestation Library", 7 | "keywords": [ 8 | "credentials", 9 | "anchor", 10 | "attestation" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/identity-com/credential-commons-js.git" 15 | }, 16 | "main": "dist/cjs/index.js", 17 | "module": "dist/es/index.js", 18 | "browser": "dist/browser/index.js", 19 | "scripts": { 20 | "lint": "eslint . --max-warnings=0", 21 | "lint:fix": "npm run lint -- --fix", 22 | "test": "cross-env NODE_ENV=test jest", 23 | "test:watch": "jest --watch", 24 | "check": "npm run lint && npm run test", 25 | "generate-civic-config": "cross-env NODE_ENV=test node scripts/configuration.js", 26 | "build:cjs": "BABEL_ENV=cjs babel src -d dist/cjs", 27 | "build:es": "babel src -d dist/es --no-babelrc", 28 | "build:browser:before": "BABEL_ENV=browser babel src -d dist/prebrowser", 29 | "build:browser:after": "minify dist/prebrowser -d dist/browser", 30 | "build:browser:clean": "rimraf dist/prebrowser", 31 | "build:browser": "npm run build:browser:before && npm run build:browser:after && npm run build:browser:clean", 32 | "build": "npm run build:browser && npm run build:cjs && npm run build:es", 33 | "pretag": "git fetch --tags", 34 | "tag": "git tag v$npm_package_version && git push --tags origin master", 35 | "precommit": "npm run lint", 36 | "release:create": "hub release create -m v$npm_package_version v$npm_package_version", 37 | "audit-ci": "audit-ci --config audit-ci.json" 38 | }, 39 | "devDependencies": { 40 | "@babel/cli": "^7.14.5", 41 | "@babel/core": "^7.14.6", 42 | "@babel/plugin-transform-runtime": "^7.14.5", 43 | "@babel/preset-env": "^7.14.7", 44 | "audit-ci": "^3.2.0", 45 | "babel-jest": "^27.0.6", 46 | "babel-minify": "^0.5.1", 47 | "clear": "^0.1.0", 48 | "cross-env": "^7.0.3", 49 | "eslint": "^7.32.0", 50 | "eslint-config-airbnb": "^17.0.0", 51 | "eslint-config-airbnb-base": "^13.0.0", 52 | "eslint-loader": "^2.0.0", 53 | "eslint-plugin-import": "^2.23.3", 54 | "eslint-plugin-jsx-a11y": "^6.1.1", 55 | "eslint-plugin-no-only-tests": "^2.6.0", 56 | "eslint-plugin-react": "^7.23.2", 57 | "figlet": "^1.5.0", 58 | "husky": "^1.1.2", 59 | "inquirer": "^7.3.3", 60 | "jest": "^25.5.4", 61 | "jest-html-reporter": "^2.3.0", 62 | "npm": "^6.14.13", 63 | "request-debug": "^0.2.0", 64 | "rimraf": "^2.6.2", 65 | "shelljs": "^0.8.4" 66 | }, 67 | "dependencies": { 68 | "@digitalbazaar/did-io": "^1.1.0", 69 | "@identity.com/did-io-driver-sol": "^1.0.0-beta.0", 70 | "@identity.com/uca": "github:identity-com/uca#v1.0.30", 71 | "ajv": "^7.2.4", 72 | "ajv-formats": "^1.6.1", 73 | "babel-runtime": "^6.26.0", 74 | "bitcoinjs-lib": "https://github.com/dabura667/bitcoinjs-lib.git#bcash330", 75 | "bottlejs": "^1.7.1", 76 | "bs58": "^4.0.1", 77 | "dotenv": "^8.6.0", 78 | "flat": "^4.1.0", 79 | "json-schema-traverse": "^1.0.0", 80 | "lodash": "^4.17.21", 81 | "merkle-tools": "^1.4.1", 82 | "moment-mini": "^2.24.0", 83 | "randexp": "^0.5.3", 84 | "randomstring": "^1.2.1", 85 | "request": "^2.88.2", 86 | "request-promise-native": "^1.0.9", 87 | "sift": "^13.5.4", 88 | "sjcl": "github:civicteam/sjcl#v1.0.8-ecc", 89 | "tweetnacl": "^1.0.3", 90 | "type-of-is": "^3.5.1", 91 | "unix-timestamp": "^0.2.0", 92 | "uuid": "^3.3.2", 93 | "valid-url": "^1.0.9" 94 | }, 95 | "jest": { 96 | "modulePathIgnorePatterns": [ 97 | "/dist/" 98 | ], 99 | "collectCoverageFrom": [ 100 | "**/src/**/*.{js}", 101 | "!**/node_modules/**", 102 | "!**/build/**", 103 | "!**/vendor/**", 104 | "!src/services/DummyAnchorServiceImpl.js", 105 | "!src/services/anchorService.js" 106 | ], 107 | "coverageThreshold": { 108 | "global": { 109 | "branches": 85, 110 | "functions": 85, 111 | "lines": 85, 112 | "statements": 85 113 | } 114 | }, 115 | "coverageDirectory": "reports/coverage", 116 | "collectCoverage": true, 117 | "testResultsProcessor": "./node_modules/jest-html-reporter", 118 | "verbose": true, 119 | "transformIgnorePatterns": [ 120 | "/node_modules/(?!(@digitalbazaar/did-io|@digitalbazaar/lru-memoize|@digitalbazaar/ed25519-verification-key-2018|@digitalbazaar/did-io|base58-universal))" 121 | ], 122 | "moduleNameMapper": { 123 | "@digitalbazaar/did-io": "@digitalbazaar/did-io/lib/main.js", 124 | "@digitalbazaar/lru-memoize": "@digitalbazaar/lru-memoize/lib/main.js", 125 | "@digitalbazaar/ed25519-verification-key-2018": "@digitalbazaar/ed25519-verification-key-2018/src/main.js", 126 | "base58-universal": "base58-universal/main.js" 127 | } 128 | }, 129 | "jest-html-reporter": { 130 | "pageTitle": "Verifiable Credential and Attestation Library Test Suite", 131 | "outputPath": "reports/test-report.html", 132 | "includeFailureMsg": true 133 | }, 134 | "husky": { 135 | "hooks": { 136 | "pre-commit": "npm run lint" 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /scripts/configuration.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const chalk = require('chalk'); 3 | const clear = require('clear'); 4 | const figlet = require('figlet'); 5 | const inquirer = require('inquirer'); 6 | const fs = require('fs'); 7 | const shell = require('shelljs'); 8 | const homedir = require('os').homedir(); 9 | 10 | 11 | /** 12 | * Defined options for the Schema Generator UCA/Credentials or Both 13 | */ 14 | const askOptions = () => { 15 | const questions = [ 16 | { 17 | type: 'input', 18 | name: 'CIVIC_SEC_URL', 19 | message: 'CIVIC_SEC_URL', 20 | }, 21 | { 22 | type: 'input', 23 | name: 'CIVIC_ATTN_URL', 24 | message: 'CIVIC_ATTN_URL', 25 | }, 26 | { 27 | type: 'input', 28 | name: 'CIVIC_CLIENT_ID', 29 | message: 'CIVIC_CLIENT_ID', 30 | }, 31 | { 32 | type: 'input', 33 | name: 'CIVIC_CLIENT_XPUB', 34 | message: 'CIVIC_CLIENT_XPUB', 35 | }, 36 | { 37 | type: 'input', 38 | name: 'CIVIC_CLIENT_XPRV', 39 | message: 'CIVIC_CLIENT_XPRV', 40 | }, 41 | { 42 | type: 'input', 43 | name: 'CIVIC_PASSPHRASE', 44 | message: 'CIVIC_PASSPHRASE', 45 | }, 46 | { 47 | type: 'input', 48 | name: 'CIVIC_KEYCHAIN', 49 | message: 'CIVIC_KEYCHAIN', 50 | }, 51 | { 52 | type: 'input', 53 | name: 'CLIENT_WALLET_ID', 54 | message: 'CLIENT_WALLET_ID', 55 | }, 56 | { 57 | type: 'input', 58 | name: 'CLIENT_WALLET_PASSPHRASE', 59 | message: 'CLIENT_WALLET_PASSPHRASE', 60 | }, 61 | { 62 | type: 'input', 63 | name: 'CLIENT_ACCESS_TOKEN', 64 | message: 'CLIENT_ACCESS_TOKEN', 65 | }, 66 | ]; 67 | return inquirer.prompt(questions); 68 | }; 69 | 70 | /** 71 | * Generate the JSON from an UCA Identifier than generate it's schema saving it on the file system 72 | * @returns {Promise} 73 | */ 74 | const generateCivicEnvCredentials = async (values) => { 75 | let envCivicFileContent = ''; 76 | const keys = Object.keys(values); 77 | keys.forEach((key) => { 78 | envCivicFileContent += `${key}=${values[key]}\n`; 79 | }); 80 | const path = `${homedir}/.civic/`; 81 | if (!fs.exists(path)) { 82 | shell.mkdir('-p', path); 83 | } 84 | fs.writeFile(`${path}config`, envCivicFileContent, (err) => { 85 | if (err) throw err; 86 | console.log('Civic credentials file successfully created'); 87 | }); 88 | }; 89 | 90 | const generate = async () => { 91 | clear(); 92 | console.log( 93 | chalk.green( 94 | figlet.textSync('CIVIC', { horizontalLayout: 'full' }), 95 | ), 96 | ); 97 | 98 | const selectedOption = await askOptions(); 99 | await generateCivicEnvCredentials(selectedOption); 100 | }; 101 | 102 | generate(); 103 | 104 | -------------------------------------------------------------------------------- /scripts/description.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const ucaDefinitions = require('../src/uca/definitions'); 3 | 4 | console.log('Attestable Values'); 5 | console.log('================='); 6 | console.log('This UCA are used as metadata or internal values not user Pii'); 7 | console.log(''); 8 | 9 | _.forEach(_.filter(ucaDefinitions, { attestable: true }), (def) => { 10 | console.log(def.identifier); 11 | console.log(def.description); 12 | }); 13 | 14 | console.log(''); 15 | console.log('Credential Items'); 16 | console.log('================='); 17 | console.log('This UCA are used as credential item and represent units of user Pii'); 18 | console.log(''); 19 | 20 | _.forEach(_.filter(ucaDefinitions, { credentialItem: true }), (def) => { 21 | console.log(def.identifier); 22 | console.log(def.description); 23 | }); 24 | 25 | console.log(''); 26 | console.log('Types'); 27 | console.log('================='); 28 | console.log('This UCA are data collected but not attested'); 29 | console.log(''); 30 | 31 | _.forEach(_.filter(ucaDefinitions, { credentialItem: false }), (def) => { 32 | console.log(def.identifier); 33 | console.log(def.description); 34 | }); 35 | -------------------------------------------------------------------------------- /scripts/generateSampleCredential.js: -------------------------------------------------------------------------------- 1 | const VC = require('../src/creds/VerifiableCredential'); 2 | const UCA = require('../src/uca/UserCollectableAttribute'); 3 | 4 | const generateSampleBasicCredentials = async () => { 5 | const email = { 6 | username: 'savio', 7 | domain: { 8 | name: 'gmail', 9 | tld: 'com', 10 | }, 11 | }; 12 | const emailUca = new UCA('claim-cvc:Contact.email-v1', email); 13 | 14 | const phoneNumber = { 15 | country: 'BR', 16 | countryCode: '55', 17 | number: '31999998888', 18 | lineType: 'mobile', 19 | }; 20 | 21 | const phoneNumberUca = new UCA('claim-cvc:Contact.phoneNumber-v1', phoneNumber); 22 | 23 | const emailCredential = new VC('cvc:Credential:Email', 'did:ethr:0xaf9482c84De4e2a961B98176C9f295F9b6008BfD', null, [emailUca], 1); 24 | const emailCredentialTemporary = await emailCredential.requestAnchor(); 25 | const emailCredentialDefinitive = await emailCredentialTemporary.updateAnchor(); 26 | console.log(JSON.stringify(emailCredentialDefinitive, null, 2)); 27 | 28 | const phoneNumberCredential = new VC('cvc:Credential:PhoneNumber', 'did:ethr:0xaf9482c84De4e2a961B98176C9f295F9b6008BfD', null, [phoneNumberUca], 1); 29 | const phoneNumberCredentialTemporary = await phoneNumberCredential.requestAnchor(); 30 | const phoneNumberCredentialDefinitive = await phoneNumberCredentialTemporary.updateAnchor(); 31 | console.log(JSON.stringify(phoneNumberCredentialDefinitive, null, 2)); 32 | }; 33 | 34 | const generateSampleAddress = async () => { 35 | const address = { 36 | street: 'Alameda dos Anjos', 37 | unit: '500', 38 | city: 'Belo Horizonte', 39 | postalCode: '94103345', 40 | state: 'Minas Gerais', 41 | county: 'Sao Bento', 42 | country: 'Brazil', 43 | }; 44 | const addressUca = new UCA('claim-cvc:Identity.address-v1', address); 45 | const civicAddress = new VC('cvc:Credential:Address', 'did:ethr:0xaf9482c84De4e2a961B98176C9f295F9b6008BfD', 315569260 /* 10y */, [addressUca], 1); 46 | civicAddress.requestAnchor().then((updatedCredential) => { 47 | updatedCredential.updateAnchor().then((definitive) => { 48 | console.log(JSON.stringify(definitive, null, 2)); 49 | }); 50 | }); 51 | }; 52 | 53 | const main = async () => { 54 | console.log('---------------------------------------------------'); 55 | await generateSampleBasicCredentials(); 56 | console.log('---------------------------------------------------'); 57 | await generateSampleAddress(); 58 | }; 59 | 60 | main().then(() => console.log('DONE')).catch(err => console.error(err)); 61 | -------------------------------------------------------------------------------- /src/AggregationHandler.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | 3 | const validateEmptyParametersOperators = (parameters) => { 4 | if (!_.isEmpty(parameters)) { throw new Error('parameters should be empty'); } 5 | return true; 6 | }; 7 | const validateNotEmptyParametersOperators = (parameters) => { 8 | if (!parameters && _.isEmpty(parameters)) { throw new Error('parameters should not be empty'); } 9 | return true; 10 | }; 11 | const validatePathParametersOperators = (parameters) => { 12 | if (!_.isString(parameters)) { throw new Error('parameters should be string'); } 13 | return true; 14 | }; 15 | const validateNumberParametersOperators = (parameters) => { 16 | if (!_.isNumber(parameters)) { throw new Error('parameters should be number'); } 17 | return true; 18 | }; 19 | const validateObjectParametersOperators = (parameters) => { 20 | if (!_.isObject(parameters)) { throw new Error('parameters should be object'); } 21 | return true; 22 | }; 23 | 24 | const sort = (colllection, params) => { 25 | const path = _.keys(params)[0]; 26 | const order = params[path]; 27 | const ordered = _.sortBy(colllection, path); 28 | return order === 'ASC' ? ordered : _.reverse(ordered); 29 | }; 30 | 31 | const AGGREGATION_OPERATORS_MAP = { 32 | none: (collection, params) => (validateEmptyParametersOperators(params) 33 | ? [...collection] : null), 34 | $limit: (collection, params) => (validateNumberParametersOperators(params) 35 | ? [...(_.slice(collection, 0, params))] : null), 36 | $min: (collection, params) => (validatePathParametersOperators(params) 37 | ? [(_.minBy(collection, params))] : null), 38 | $max: (collection, params) => (validatePathParametersOperators(params) 39 | ? [(_.maxBy(collection, params))] : null), 40 | $first: (collection, params) => (validateNotEmptyParametersOperators(params) 41 | ? [_.first(collection)] : null), 42 | $last: (collection, params) => (validateNotEmptyParametersOperators(params) 43 | ? [_.last(collection)] : null), 44 | $sort: (collection, params) => (validateObjectParametersOperators(params) 45 | ? [...(sort(collection, params))] : null), 46 | }; 47 | 48 | function aggregate(credentials, stages) { 49 | let filtered = [...credentials]; 50 | _.forEach(stages, (stage) => { 51 | const operator = _.keys(stage)[0]; 52 | 53 | if (!_.includes(_.keys(AGGREGATION_OPERATORS_MAP), operator)) { 54 | throw new Error(`Invalid operator: ${operator}`); 55 | } 56 | const params = stage[operator]; 57 | const operatorImplementation = AGGREGATION_OPERATORS_MAP[operator]; 58 | filtered = operatorImplementation(filtered, params); 59 | }); 60 | return filtered; 61 | } 62 | 63 | module.exports = aggregate; 64 | -------------------------------------------------------------------------------- /src/SecureRandom.js: -------------------------------------------------------------------------------- 1 | const sjcl = require('sjcl'); 2 | const logger = require('./logger'); 3 | 4 | class SecureRandom { 5 | constructor(seedHexString) { 6 | logger.debug('Init Secure Random'); 7 | // eslint-disable-next-line new-cap 8 | this.sjclRandom = new sjcl.prng(10); 9 | 10 | if (seedHexString) { 11 | const seed = sjcl.codec.hex.toBits(seedHexString); 12 | this.sjclRandom.addEntropy(seed, undefined, 'csprng'); 13 | this.isSeeded = true; 14 | } else { 15 | try { 16 | logger.debug('Trying crypto'); 17 | /* eslint-disable global-require */ 18 | const hexString = require('crypto').randomBytes(1024).toString('hex'); 19 | /* eslint-enable global-require */ 20 | const seed = sjcl.codec.hex.toBits(hexString); 21 | this.sjclRandom.addEntropy(seed, undefined, 'csprng'); 22 | this.isSeeded = true; 23 | } catch (error) { 24 | logger.warn(`Crypto: ${error}`); 25 | this.isSeeded = false; 26 | } 27 | } 28 | } 29 | 30 | wordWith(size) { 31 | if (!this.isSeeded) { 32 | throw new Error("Can't user SecureRandom before seeding"); 33 | } 34 | 35 | const randomBytes = this.sjclRandom.randomWords(size / 8, 10); 36 | return sjcl.codec.hex.fromBits(randomBytes); 37 | } 38 | } 39 | 40 | module.exports = SecureRandom; 41 | -------------------------------------------------------------------------------- /src/claim/__mocks__/definitions.js: -------------------------------------------------------------------------------- 1 | const definitions = [ 2 | { 3 | identifier: 'civ:Mock:booleans', 4 | version: '1', 5 | type: 'Boolean', 6 | attestable: true, 7 | }, 8 | { 9 | identifier: 'civ:Mock:excMax', 10 | version: '1', 11 | type: 'Number', 12 | exclusiveMaximum: true, 13 | maximum: 20, 14 | }, 15 | { 16 | identifier: 'civ:Mock:max', 17 | version: '1', 18 | type: 'Number', 19 | exclusiveMaximum: false, 20 | maximum: 50, 21 | }, 22 | { 23 | identifier: 'civ:Mock:excMax', 24 | version: '1', 25 | type: 'Number', 26 | value: [10, 20, 30], 27 | }, 28 | { 29 | identifier: 'civ:Mock:max', 30 | version: '1', 31 | type: 'Number', 32 | exclusiveMinimum: false, 33 | minimum: 5, 34 | }, 35 | ]; 36 | 37 | module.exports = definitions; 38 | -------------------------------------------------------------------------------- /src/claim/definitions.js: -------------------------------------------------------------------------------- 1 | // This exists for backwards compatibility and should be removed 2 | module.exports = []; 3 | -------------------------------------------------------------------------------- /src/constants/headers.js: -------------------------------------------------------------------------------- 1 | const HeaderType = { 2 | EXTERNAL_ID_HEADER: 'X-External-ID', 3 | FLOW_ID_HEADER: 'X-Civic-FlowId', 4 | IDENTITY_HEADER: 'X-Identity-Self', 5 | }; 6 | module.exports = { 7 | HeaderType, 8 | }; 9 | -------------------------------------------------------------------------------- /src/constants/index.js: -------------------------------------------------------------------------------- 1 | const headers = require('./headers'); 2 | 3 | module.exports = { 4 | headers, 5 | }; 6 | -------------------------------------------------------------------------------- /src/creds/ClaimModel.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | 3 | /** 4 | * Transforms a list of UCAs into the claim property of the verifiable cliams 5 | */ 6 | class ClaimModel { 7 | constructor(ucas) { 8 | _.forEach(ucas, (uca) => { 9 | const rootPropertyName = uca.getClaimRootPropertyName(); 10 | if (!_.isEmpty(rootPropertyName)) { 11 | if (!this[rootPropertyName]) { 12 | this[rootPropertyName] = {}; 13 | } 14 | 15 | this[rootPropertyName][uca.getClaimPropertyName()] = uca.getPlainValue(); 16 | } else { 17 | this[uca.getClaimPropertyName()] = uca.getPlainValue(); 18 | } 19 | }); 20 | } 21 | } 22 | 23 | module.exports = { ClaimModel }; 24 | -------------------------------------------------------------------------------- /src/creds/CredentialSignerVerifier.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const { HDNode, ECSignature } = require('bitcoinjs-lib'); 3 | 4 | const SIGNATURE_ALGO = 'ec256k1'; 5 | class CredentialSignerVerifier { 6 | /** 7 | * Creates a new instance of a CredentialSignerVerifier 8 | * 9 | * @param options.keyPair any instace that implements sign and verify interface 10 | * or 11 | * @param options.prvBase58 bse58 serialized private key 12 | * or for verification only 13 | * @param options.pubBase58 bse58 serialized public key 14 | */ 15 | constructor(options) { 16 | if (_.isEmpty(options.keyPair) && _.isEmpty(options.prvBase58) && _.isEmpty(options.pubBase58)) { 17 | throw new Error('Either a keyPair, prvBase58 or pubBase58(to verify only) is required'); 18 | } 19 | this.keyPair = options.keyPair || HDNode.fromBase58(options.prvBase58 || options.pubBase58); 20 | } 21 | 22 | /** 23 | * Verify is a credential has a valid merkletree signature, using a pinned pubkey 24 | * @param credential 25 | * @returns {*|boolean} 26 | */ 27 | isSignatureValid(credential) { 28 | if (_.isEmpty(credential.proof) 29 | || _.isEmpty(credential.proof.merkleRoot) 30 | || _.isEmpty(credential.proof.merkleRootSignature)) { 31 | throw Error('Invalid Credential Proof Schema'); 32 | } 33 | 34 | try { 35 | const signatureHex = _.get(credential, 'proof.merkleRootSignature.signature'); 36 | const signature = signatureHex ? ECSignature.fromDER(Buffer.from(signatureHex, 'hex')) : null; 37 | const merkleRoot = _.get(credential, 'proof.merkleRoot'); 38 | return (signature && merkleRoot) ? this.keyPair.verify(Buffer.from(merkleRoot, 'hex'), signature) : false; 39 | } catch (error) { 40 | // verify throws in must cases but we want to return false 41 | return false; 42 | } 43 | } 44 | 45 | /** 46 | * Create a merkleRootSignature object by signing with a pinned private key 47 | * @param proof 48 | * @returns {{signature, pubBase58: *, algo: string}} 49 | */ 50 | sign(proof) { 51 | const hash = Buffer.from(proof.merkleRoot, 'hex'); 52 | const signature = this.keyPair.sign(hash); 53 | return { 54 | algo: SIGNATURE_ALGO, 55 | pubBase58: this.keyPair.neutered().toBase58(), 56 | signature: signature.toDER().toString('hex'), 57 | }; 58 | } 59 | } 60 | 61 | module.exports = CredentialSignerVerifier; 62 | -------------------------------------------------------------------------------- /src/creds/CvcMerkleProof.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const MerkleTools = require('merkle-tools'); 3 | 4 | const { sha256 } = require('../lib/crypto'); 5 | const { Claim } = require('../claim/Claim'); 6 | const { services } = require('../services'); 7 | 8 | /** 9 | * Transforms a list of UCAs into the signature property of the verifiable claims 10 | */ 11 | class CvcMerkleProof { 12 | static get PADDING_INCREMENTS() { 13 | return 16; 14 | } 15 | 16 | constructor(ucas, credentialSigner = null) { 17 | const withRandomUcas = CvcMerkleProof.padTree(ucas); 18 | this.type = 'CvcMerkleProof2018'; 19 | this.merkleRoot = null; 20 | this.anchor = 'TBD (Civic Blockchain Attestation)'; 21 | this.leaves = CvcMerkleProof.getAllAttestableValue(withRandomUcas); 22 | this.buildMerkleTree(credentialSigner); 23 | this.granted = null; 24 | } 25 | 26 | buildMerkleTree(credentialSigner = null) { 27 | const merkleTools = new MerkleTools(); 28 | const hashes = _.map(this.leaves, n => sha256(n.value)); 29 | merkleTools.addLeaves(hashes); 30 | merkleTools.makeTree(); 31 | _.forEach(hashes, (hash, idx) => { 32 | this.leaves[idx].targetHash = hash; 33 | this.leaves[idx].node = merkleTools.getProof(idx); 34 | }); 35 | this.leaves = _.filter(this.leaves, el => !(el.identifier === 'cvc:Random:node')); 36 | this.merkleRoot = merkleTools.getMerkleRoot().toString('hex'); 37 | 38 | if (credentialSigner) { 39 | this.merkleRootSignature = credentialSigner.sign(this); 40 | } 41 | } 42 | 43 | static padTree(nodes) { 44 | const currentLength = nodes.length; 45 | const targetLength = currentLength < CvcMerkleProof.PADDING_INCREMENTS ? CvcMerkleProof.PADDING_INCREMENTS 46 | : _.ceil(currentLength / CvcMerkleProof.PADDING_INCREMENTS) * CvcMerkleProof.PADDING_INCREMENTS; 47 | const newNodes = _.clone(nodes); 48 | const secureRandom = services.container.SecureRandom; 49 | while (newNodes.length < targetLength) { 50 | newNodes.push(new Claim('cvc:Random:node', secureRandom.wordWith(16))); 51 | } 52 | return newNodes; 53 | } 54 | 55 | static getAllAttestableValue(ucas) { 56 | let values = []; 57 | _.forEach(ucas, (uca) => { 58 | const innerValues = uca.getAttestableValues(); 59 | values = _.concat(values, innerValues); 60 | }); 61 | return values; 62 | } 63 | } 64 | 65 | module.exports = { CvcMerkleProof }; 66 | -------------------------------------------------------------------------------- /src/creds/__mocks__/definitions.js: -------------------------------------------------------------------------------- 1 | const definitions = [ 2 | { 3 | identifier: 'civ:Credential:SimpleIdentity', 4 | version: '1', 5 | depends: [ 6 | 'civ:Identity:name', 7 | 'civ:Identity:DateOfBirth', 8 | ], 9 | }, 10 | { 11 | identifier: 'civ:Credential:SimpleTest', 12 | version: '1', 13 | depends: [ 14 | 'civ:Identity:name', 15 | 'civ:Identity:DateOfBirth', 16 | ], 17 | }, 18 | { 19 | identifier: 'civ:Credential:TestWithExcludes', 20 | version: '1', 21 | depends: [ 22 | 'civ:Identity:name', 23 | 'civ:Identity:DateOfBirth', 24 | ], 25 | excludes: [ 26 | 'civ:Identity:name.middle', 27 | ], 28 | }, 29 | ]; 30 | 31 | module.exports = definitions; 32 | -------------------------------------------------------------------------------- /src/creds/definitions.js: -------------------------------------------------------------------------------- 1 | // This exists for backwards compatibility and should be removed 2 | module.exports = []; 3 | -------------------------------------------------------------------------------- /src/errors/idvErrors.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const { ErrorCodes, ErrorContextTypes } = require('./definitions'); 3 | 4 | // These codes are passed in the 'name' value of the error object when the IDV-toolkit 5 | // throws an error 6 | // @deprecated - left here for retrofit, use ErrorConstants instead for future versions 7 | const IDVErrorCodes = _.pickBy(ErrorCodes, (v, k) => (k.startsWith('ERROR_IDV'))); 8 | 9 | /* 10 | * IDVError parses a HTTP Error response body from the IDV-toolkit 11 | * Usage: the IDVError can be instantiated directly from the HTTPResponse body e.g. 12 | * const idvError = new IDVError(response.body); 13 | * @param errorObj: parsed directly from the HTTP Response body which should contain 14 | * message: human readable explanation of the error e.g. 'Missing required UCA fields' 15 | * name: Error-Code, defined in IDVErrorCodes, e.g. IDVErrorCodes.ERROR_IDV_UCA_MISSING_PROPERTY 16 | * data: an array of objects with { name: "name", value: "value" } properties e.g. 17 | * [{ name: ErrorContextType.MISSING_PROPERTY, value: missingProperty }] 18 | * @returns an instance of IDVError 19 | * */ 20 | class IDVError { 21 | constructor(errorObj) { 22 | this.message = errorObj.message; 23 | this.errorCode = errorObj.name; 24 | this.errorContext = errorObj.data; 25 | } 26 | } 27 | 28 | module.exports = { 29 | IDVErrorCodes, 30 | ErrorContextTypes, 31 | IDVError, 32 | }; 33 | -------------------------------------------------------------------------------- /src/errors/index.js: -------------------------------------------------------------------------------- 1 | const idvErrors = require('./idvErrors'); 2 | const { ErrorCodes, ErrorContextTypes } = require('./definitions'); 3 | 4 | module.exports = { 5 | ErrorCodes, 6 | ErrorContextTypes, 7 | idvErrors, // For retrofit, will be deprecated on the future 8 | }; 9 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const { Claim } = require('./claim/Claim'); 2 | const { UserCollectableAttribute } = require('./uca/UCA'); 3 | const VC = require('./creds/VerifiableCredential'); 4 | const { initServices, services } = require('./services/index'); 5 | const isValidGlobalIdentifier = require('./isValidGlobalIdentifier'); 6 | const isClaimRelated = require('./isClaimRelated'); 7 | const errors = require('./errors'); 8 | const constants = require('./constants'); 9 | const claimDefinitions = require('./claim/definitions'); 10 | const credentialDefinitions = require('./creds/definitions'); 11 | const aggregate = require('./AggregationHandler'); 12 | const { schemaLoader } = require('./schemas/jsonSchema'); 13 | const CVCSchemaLoader = require('./schemas/jsonSchema/loaders/cvc'); 14 | const VCCompat = require('./creds/VerifiableCredentialProxy'); 15 | /** 16 | * Entry Point for Civic Credential Commons 17 | * @returns {CredentialCommons} 18 | * @constructor 19 | */ 20 | function CredentialCommons() { 21 | this.Claim = Claim; 22 | 23 | this.init = initServices; 24 | this.isValidGlobalIdentifier = isValidGlobalIdentifier; 25 | this.isClaimRelated = isClaimRelated; 26 | this.services = services; 27 | this.aggregate = aggregate; 28 | this.errors = errors; 29 | this.constants = constants; 30 | this.claimDefinitions = claimDefinitions; 31 | this.credentialDefinitions = credentialDefinitions; 32 | this.schemaLoader = schemaLoader; 33 | this.CVCSchemaLoader = CVCSchemaLoader; 34 | this.UserCollectableAttribute = UserCollectableAttribute; 35 | this.VC = VC; 36 | this.VCCompat = VCCompat; 37 | return this; 38 | } 39 | 40 | // to work with entry points in multi module manage the best way 41 | module.exports = new CredentialCommons(); 42 | -------------------------------------------------------------------------------- /src/isClaimRelated.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const { definitions, Claim } = require('./claim/Claim'); 3 | const vcDefinitions = require('./creds/definitions'); 4 | const { schemaLoader } = require('./schemas/jsonSchema'); 5 | /** 6 | * Validate an claim path against it's parent UserCollectableAttribute, and the parent Claim against the 7 | * dependencies of an Credential 8 | * @param claim path, eg: name.first 9 | * @param uca the global identifier for the UCA/Claim, eg: claim-civ:Identity:name-1 10 | * @param credential the parent identifier, eg: civ:Credential:GenericId 11 | * @return true if the dependency exists and false if it doesn't 12 | */ 13 | async function isClaimRelated(claim, uca, credential) { 14 | // Load the schema and it's references from a source to be used for validation and defining the schema definitions 15 | await schemaLoader.loadSchemaFromTitle(claim); 16 | await schemaLoader.loadSchemaFromTitle(uca); 17 | await schemaLoader.loadSchemaFromTitle(credential); 18 | 19 | // first get the UCA identifier 20 | const ucaIdentifier = uca.substring(uca.indexOf('-') + 1, uca.lastIndexOf('-')); 21 | // Load the schema and it's references from a source to be used for validation and defining the schema definitions 22 | await schemaLoader.loadSchemaFromTitle(ucaIdentifier); 23 | 24 | // check on the credential commons if this identifier exists 25 | const ucaDefinition = definitions.find(definition => definition.identifier === ucaIdentifier); 26 | // does the UCA exist? 27 | if (ucaDefinition) { 28 | const ucaProperties = await Claim.getAllProperties(ucaIdentifier); 29 | 30 | // does the claim exists in the Claim? 31 | if (_.includes(ucaProperties, claim)) { 32 | // we now have the composite uca, the uca for the claim property, they both are correct 33 | // we need to check now the UCA is inside the dependencies of the credential refered as parent 34 | const credentialDefinition = vcDefinitions.find(definition => ( 35 | definition.identifier === credential 36 | )); 37 | if (credentialDefinition) { 38 | return _.includes(credentialDefinition.depends, ucaIdentifier); 39 | } 40 | throw new Error('Credential identifier does not exist'); 41 | } else { 42 | throw new Error('Claim property path does not exist on UCA definitions'); 43 | } 44 | } else { 45 | // return error about wrong uca identifier 46 | throw new Error('UCA identifier does not exist'); 47 | } 48 | } 49 | 50 | module.exports = isClaimRelated; 51 | -------------------------------------------------------------------------------- /src/isValidGlobalIdentifier.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const { schemaLoader } = require('./schemas/jsonSchema'); 3 | 4 | const validUCAIdentifiers = schemaLoader.validIdentifiers; 5 | const validClaimIdentifiers = schemaLoader.validIdentifiers; 6 | const validVCIdentifiers = schemaLoader.validCredentialIdentifiers; 7 | const validPrefixes = ['claim', 'credential']; 8 | 9 | async function isValidGlobalIdentifier(identifier) { 10 | // Load the schema and it's references from a source to be used for validation and defining the schema definitions 11 | await schemaLoader.loadSchemaFromTitle(identifier); 12 | 13 | const splited = _.split(identifier, '-'); 14 | 15 | if (splited.length !== 3) { 16 | throw new Error('Malformed Global Identifier'); 17 | } 18 | 19 | if (!_.includes(validPrefixes, splited[0])) { 20 | throw new Error('Invalid Global Identifier Prefix'); 21 | } 22 | 23 | switch (splited[0]) { 24 | case 'claim': 25 | if (!_.includes(validUCAIdentifiers, splited[1]) && !_.includes(validClaimIdentifiers, identifier)) { 26 | throw new Error(`${identifier} is not valid`); 27 | } 28 | return true; 29 | case 'credential': 30 | if (!_.includes(validVCIdentifiers, splited[1]) && !_.includes(validVCIdentifiers, identifier)) { 31 | throw new Error(`${identifier} is not valid`); 32 | } 33 | return true; 34 | default: 35 | return false; 36 | } 37 | } 38 | 39 | module.exports = isValidGlobalIdentifier; 40 | -------------------------------------------------------------------------------- /src/lib/crypto.js: -------------------------------------------------------------------------------- 1 | const sjcl = require('sjcl'); 2 | 3 | const sha256 = stringToHash => sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(stringToHash)); 4 | 5 | module.exports = { 6 | sha256, 7 | }; 8 | -------------------------------------------------------------------------------- /src/lib/did.js: -------------------------------------------------------------------------------- 1 | const { 2 | findVerificationMethod, 3 | CachedResolver, 4 | } = require('@digitalbazaar/did-io'); 5 | const didSol = require('@identity.com/did-io-driver-sol').default; 6 | 7 | const resolver = new CachedResolver(); 8 | 9 | // no payer needed as we are only resolving documents 10 | resolver.use(didSol.driver({ payer: null })); 11 | 12 | module.exports = { 13 | /** 14 | * Checks if a verificationMethod can sign for the DID document 15 | * 16 | * @param didOrDocument A DID (string) or DID document (object) 17 | * @param verificationMethod The verification method to check 18 | * @returns {Promise} True if the verification method can sign 19 | */ 20 | async canSign(didOrDocument, verificationMethod) { 21 | const [verificationMethodDid] = verificationMethod.split('#'); 22 | const document = didOrDocument.id ? didOrDocument : (await this.resolve(didOrDocument)); 23 | 24 | const did = document.id; 25 | 26 | // if the verificationMethod DID is for the document DID 27 | if (verificationMethodDid === did) { 28 | return this.findVerificationMethod(document, verificationMethod) !== null; 29 | } 30 | 31 | if (!document.controller.includes(verificationMethodDid)) { 32 | // If the verification method DID is not a controller of the provided DID 33 | return false; 34 | } 35 | 36 | // Check if the verificationMethod exists on the controller DID document 37 | const controllerDocument = await this.resolve(verificationMethodDid); 38 | return this.findVerificationMethod(controllerDocument, verificationMethod) !== null; 39 | }, 40 | 41 | /** 42 | * Resolves a DID document 43 | * 44 | * @param did The DID to resolve the document for 45 | */ 46 | async resolve(did) { 47 | return resolver.get({ did }); 48 | }, 49 | 50 | /** 51 | * Finds the verificationMethod in a document 52 | * 53 | * @param document The document to search through 54 | * @param verificationMethod The verification method to return 55 | */ 56 | findVerificationMethod(document, verificationMethod) { 57 | if (document.keyAgreement && document.keyAgreement.length > 0) { 58 | return document.keyAgreement.find(agreement => agreement.id === verificationMethod); 59 | } 60 | 61 | if (!document.capabilityInvocation.includes(verificationMethod)) { 62 | return null; 63 | } 64 | 65 | return findVerificationMethod({ 66 | doc: document, 67 | methodId: verificationMethod, 68 | }); 69 | }, 70 | }; 71 | -------------------------------------------------------------------------------- /src/lib/signerVerifier.js: -------------------------------------------------------------------------------- 1 | const nacl = require('tweetnacl'); 2 | const bs58 = require('bs58'); 3 | const didUtil = require('./did'); 4 | 5 | class Ed25519Signer { 6 | constructor(key, verificationMethod) { 7 | this.key = key; 8 | this.verificationMethod = verificationMethod; 9 | } 10 | 11 | sign(proof) { 12 | const signed = nacl.sign.detached(Buffer.from(proof.merkleRoot, 'hex'), bs58.decode(this.key)); 13 | const signature = Buffer.from(signed).toString('hex'); 14 | 15 | return { 16 | signature, 17 | verificationMethod: this.verificationMethod, 18 | }; 19 | } 20 | } 21 | 22 | class Ed25519Verifier { 23 | constructor(key) { 24 | this.key = key; 25 | } 26 | 27 | verify(vc) { 28 | return this.verifyEncoding(vc, 'hex') || this.verifyEncoding(vc, 'utf-8'); 29 | } 30 | 31 | /** 32 | * Verifies a VC that was signed with a specific encoding 33 | */ 34 | verifyEncoding(vc, encoding) { 35 | return nacl.sign.detached.verify( 36 | Buffer.from(vc.proof.merkleRoot, encoding), 37 | Uint8Array.from(Buffer.from(vc.proof.merkleRootSignature.signature, 'hex')), 38 | bs58.decode(this.key), 39 | ); 40 | } 41 | } 42 | 43 | /** 44 | * Creates a signer from the provided information 45 | * 46 | * @param options Signer options: 47 | * @param options.verificationMethod The verificationMethod for the signing key 48 | * @param options.keypair The keypair to sign with 49 | * or 50 | * @param options.privateKey The private key to sign with 51 | * or 52 | * @param options.signer An object implementing a `sign(CvcMerkleProof)` method 53 | */ 54 | const signer = async (options) => { 55 | if (!options.signer && !options.keypair && !options.privateKey) { 56 | throw new Error('Either a signer, keypair or privateKey is required'); 57 | } 58 | 59 | const { verificationMethod } = options; 60 | let { signer: signerImpl } = options; 61 | 62 | // Create a signer from keypair/key 63 | if (signerImpl) return signerImpl; 64 | 65 | const [did] = verificationMethod.split('#'); 66 | 67 | const document = await didUtil.resolve(did); 68 | 69 | let { privateKey } = options; 70 | if (!privateKey) { 71 | privateKey = bs58.encode(options.keypair.secretKey); 72 | } 73 | 74 | const foundMethod = didUtil.findVerificationMethod(document, verificationMethod); 75 | if (!foundMethod) { 76 | throw new Error('The provided verificationMethod is not valid on the DID document'); 77 | } 78 | 79 | // Check the type is supported and assign the appropriate signer 80 | switch (foundMethod.type) { 81 | case 'Ed25519VerificationKey2018': 82 | case 'Ed25519VerificationKey2020': 83 | signerImpl = new Ed25519Signer(privateKey, verificationMethod); 84 | break; 85 | default: 86 | throw new Error(`Unsupported type ${foundMethod.type}`); 87 | } 88 | 89 | return signerImpl; 90 | }; 91 | 92 | /** 93 | * Creates a verifier based on the information provided 94 | * @param did The issuer DID 95 | * @param verificationMethod The verification method used to lookup the key 96 | */ 97 | const verifier = async (did, verificationMethod) => { 98 | const canSignFor = await didUtil.canSign(did, verificationMethod); 99 | if (!canSignFor) { 100 | // always return false 101 | return { 102 | verify: () => false, 103 | }; 104 | } 105 | 106 | const [vmDid] = verificationMethod.split('#'); 107 | const document = await didUtil.resolve(vmDid); 108 | const foundMethod = didUtil.findVerificationMethod(document, verificationMethod); 109 | 110 | // Check the type is supported and assign the appropriate verifier 111 | switch (foundMethod.type) { 112 | case 'Ed25519VerificationKey2018': 113 | case 'Ed25519VerificationKey2020': 114 | return new Ed25519Verifier(foundMethod.publicKeyBase58); 115 | default: 116 | throw new Error(`Unsupported type ${foundMethod.type}`); 117 | } 118 | }; 119 | 120 | module.exports = { 121 | signer, 122 | verifier, 123 | }; 124 | -------------------------------------------------------------------------------- /src/lib/stringUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert strings like "SocialSecurity" to "socialSecurity". 3 | * If passed a non-PascalCase string such as SOCIAL_SECURITY, it cannot detect that the string 4 | * is not PascalCase and will therefore convert it to sOCIAL_SECURITY 5 | * @param string 6 | * @return {*} 7 | */ 8 | const pascalToCamelCase = string => string.replace(/^([A-Z])/, match => match.toLowerCase()); 9 | 10 | const identifierPattern = /(claim|credential|uca|type)-((\w+):[\w.:]+)-v(\d+)/; 11 | const parseIdentifier = identifier => identifier.match(identifierPattern); 12 | 13 | module.exports = { 14 | pascalToCamelCase, 15 | parseIdentifier, 16 | }; 17 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // eslint-disable-next-line no-unused-vars 3 | warn(a, b = undefined) { 4 | // eslint-disable-next-line no-console 5 | console.warn(a); 6 | }, 7 | // eslint-disable-next-line no-unused-vars 8 | info(a, b = undefined) { 9 | // eslint-disable-next-line no-console 10 | console.info(a); 11 | }, 12 | // eslint-disable-next-line no-unused-vars 13 | debug(a, b = undefined) { 14 | // eslint-disable-next-line no-console 15 | // console.debug(a); // disabled 16 | }, 17 | // eslint-disable-next-line no-unused-vars 18 | error(a, b = undefined) { 19 | // eslint-disable-next-line no-console 20 | console.error(a); 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/schemas/jsonSchema/loaders/cvc.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { parseIdentifier } = require('../../../lib/stringUtils'); 3 | const { services } = require('../../../services'); 4 | 5 | const rootUri = 'http://identity.com/schemas/'; 6 | const DEFAULT_SCHEMA_PATH = 'http://dev-schemas.civic.com.s3-website-us-east-1.amazonaws.com/dev'; 7 | 8 | class FSSchemaCache { 9 | constructor(cachePath = './.tmp/schemas') { 10 | this.cachePath = cachePath; 11 | fs.mkdirSync(cachePath, { recursive: true }); 12 | } 13 | 14 | get(identifier) { 15 | const cachePath = `${this.cachePath}/${identifier}.schema.json`; 16 | if (!fs.existsSync(cachePath)) { 17 | return null; 18 | } 19 | 20 | return fs.readFileSync(cachePath, { encoding: 'utf8' }); 21 | } 22 | 23 | set(identifier, schema) { 24 | const cachePath = `${this.cachePath}/${identifier}.schema.json`; 25 | 26 | fs.writeFileSync(cachePath, schema, { encoding: 'utf8' }); 27 | } 28 | } 29 | 30 | const getIdentifierPath = (identifier) => { 31 | let identifierPath; 32 | 33 | if (/^cvc:.*$/.test(identifier)) { 34 | identifierPath = `uca/1/${identifier}`; 35 | } else { 36 | const parsedIdentifier = parseIdentifier(identifier); 37 | 38 | if (parsedIdentifier) { 39 | identifierPath = `${parsedIdentifier[1]}/${parsedIdentifier[4]}/${parsedIdentifier[2]}`; 40 | } 41 | } 42 | 43 | return identifierPath; 44 | }; 45 | 46 | /** 47 | * This is a sample schema loader, to be used for testing or civic.com claims & credential implementations 48 | */ 49 | class CVCLoader { 50 | constructor(http = services.container.Http, cache = new FSSchemaCache(), schemaPath = DEFAULT_SCHEMA_PATH) { 51 | this.http = http; 52 | this.cache = cache; 53 | this.schemaPath = schemaPath; 54 | } 55 | 56 | /** 57 | * Gets the schema id based on the identifier 58 | */ 59 | // eslint-disable-next-line class-methods-use-this 60 | schemaId(identifier) { 61 | return rootUri + identifier; 62 | } 63 | 64 | /** 65 | * Tests to see if this loader is valid for the supplied identifier 66 | */ 67 | // eslint-disable-next-line class-methods-use-this 68 | valid(identifier) { 69 | return /^(claim|credential|type)-(cvc|alt):.*$/.test(identifier) || /^cvc:.*$/.test(identifier); 70 | } 71 | 72 | /** 73 | * Loads the schema based on the identifier 74 | */ 75 | async loadSchema(identifier) { 76 | let schema = null; 77 | if (this.cache) { 78 | schema = this.cache.get(identifier); 79 | } 80 | 81 | // Only load the schema remotely if a base url was provided and none was found locally 82 | if (!schema) { 83 | schema = await this.remote(identifier); 84 | 85 | if (this.cache && schema) { 86 | this.cache.set(identifier, schema); 87 | } 88 | } 89 | 90 | try { 91 | return !schema ? null : JSON.parse(schema); 92 | } catch (e) { 93 | return null; 94 | } 95 | } 96 | 97 | /** 98 | * Loads a schema from a remote location 99 | * @param identifier The identifer to load the schema for 100 | * @returns The schema object if found 101 | */ 102 | async remote(identifier) { 103 | const identifierPath = getIdentifierPath(identifier); 104 | 105 | if (!identifierPath) { 106 | return null; 107 | } 108 | 109 | const uri = `${this.schemaPath}/${identifierPath}.schema.json`; 110 | 111 | let response = null; 112 | try { 113 | response = await this.http.request(uri); 114 | } catch (e) { 115 | // If it fails due to timeout/connectivity, or a server side issue - try again 116 | if (!e.statusCode || (e.statusCode >= 500 && e.statusCode <= 599)) { 117 | response = await services.container.Http.request(uri); 118 | } else if (e.statusCode < 400 || e.statusCode >= 500) { 119 | throw e; 120 | } 121 | } 122 | 123 | return response; 124 | } 125 | } 126 | 127 | module.exports = CVCLoader; 128 | -------------------------------------------------------------------------------- /src/services/DefaultAnchorServiceImpl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Current Anchor/Attester service 3 | * 4 | */ 5 | const uuid = require('uuid/v4'); 6 | const { HDNode, ECSignature } = require('bitcoinjs-lib'); 7 | const sjcl = require('sjcl'); 8 | const logger = require('../logger'); 9 | 10 | /** 11 | * An Anchor/Attester implementation 12 | * 13 | * @param {*} config 14 | * @param {*} http 15 | */ 16 | function DummyAnchorServiceImpl(config, http) { 17 | this.config = config; 18 | this.http = http; 19 | // eslint-disable-next-line no-unused-vars 20 | const pollService = async (statusUrl) => { 21 | try { 22 | const attestation = await this.http.request({ 23 | url: statusUrl, 24 | method: 'GET', 25 | simple: true, 26 | json: true, 27 | }); 28 | 29 | if (!attestation || !attestation.type) { 30 | // eslint-disable-next-line no-unused-vars 31 | return await pollService(statusUrl); 32 | } 33 | if (attestation && attestation.type !== 'permanent') { 34 | attestation.statusUrl = statusUrl; 35 | return attestation; 36 | } 37 | return attestation; 38 | } catch (error) { 39 | logger.error(`Error polling: ${statusUrl}`, JSON.stringify(error, null, 2)); 40 | throw new Error(`Error polling: ${statusUrl}`); 41 | } 42 | }; 43 | 44 | this.anchor = async (options = {}) => ( 45 | Promise.resolve({ 46 | subject: { 47 | pub: 'xpub:dummy', 48 | label: options.subject && options.subject.label ? options.subject.label : null, 49 | data: options.subject && options.subject.data ? options.subject.data : null, 50 | signature: 'signed:dummy', 51 | }, 52 | walletId: 'none', 53 | cosigners: [{ 54 | pub: 'xpub:dummy', 55 | }, { 56 | pub: 'xpub:dummy', 57 | }], 58 | authority: { 59 | pub: 'xpub:dummy', 60 | path: '/', 61 | }, 62 | coin: 'dummycoin', 63 | tx: uuid(), 64 | network: 'dummynet', 65 | type: 'temporary', 66 | civicAsPrimary: false, 67 | schema: 'dummy-20180201', 68 | }) 69 | ); 70 | 71 | this.update = async (tempAnchor) => { 72 | tempAnchor.type = 'permanent'; // eslint-disable-line 73 | tempAnchor.value = new uuid(); // eslint-disable-line 74 | return Promise.resolve(tempAnchor); 75 | }; 76 | 77 | this.verifySignature = (proof, pinnedPubKey) => { 78 | const { subject } = proof.anchor; 79 | const anchorSubjectValidation = this.verifySubjectSignature(subject, pinnedPubKey); 80 | return anchorSubjectValidation && (subject.data === proof.merkleRoot); 81 | }; 82 | 83 | /** 84 | * This method checks if the subject signature matches the pub key 85 | * @param subject a json with label, data, signature, pub 86 | * @returns {*} true or false for the validation 87 | */ 88 | this.verifySubjectSignature = (subject, pinnedPubKey) => { 89 | // Do not use JS destruct on the next line, We need to predict the JSON order 90 | const toHash = JSON.stringify({ xpub: subject.pub, label: subject.label, data: subject.data }); 91 | const hash = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(toHash)); 92 | const subjectSignature = ECSignature.fromDER(Buffer.from(subject.signature, 'hex')); 93 | return HDNode.fromBase58(pinnedPubKey || subject.pub).keyPair.verify(Buffer.from(hash, 'hex'), subjectSignature); 94 | }; 95 | 96 | /** 97 | * This method checks that the attestation / anchor exists on the BC 98 | */ 99 | this.verifyAttestation = async (proof, offline = true) => { 100 | const path = '/proof'; 101 | const endpoint = `${this.config.attestationService}${path}`; 102 | 103 | const requestOptions = { 104 | url: endpoint, 105 | body: { attestation: proof.anchor, offline }, 106 | method: 'POST', 107 | json: true, 108 | simple: true, // reject if not 2XX 109 | }; 110 | 111 | const response = await this.http.request(requestOptions); 112 | return response.valid; 113 | }; 114 | 115 | this.revokeAttestation = async (signature) => { 116 | signature.revoked = true; // eslint-disable-line 117 | return Promise.resolve(signature); 118 | }; 119 | 120 | this.isRevoked = signature => (signature.revoked ? signature.revoked : false); 121 | 122 | return this; 123 | } 124 | 125 | module.exports = { 126 | CurrentCivicAnchor: DummyAnchorServiceImpl, 127 | }; 128 | -------------------------------------------------------------------------------- /src/services/DummyAnchorServiceImpl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Current Anchor/Attester service 3 | * 4 | */ 5 | const uuid = require('uuid/v4'); 6 | const logger = require('../logger'); 7 | 8 | /** 9 | * An Anchor/Attester implementation 10 | * 11 | * @param {*} config 12 | * @param {*} http 13 | */ 14 | function DummyAnchorServiceImpl(config, http) { 15 | this.config = config; 16 | this.http = http; 17 | // eslint-disable-next-line no-unused-vars 18 | const pollService = async (statusUrl) => { 19 | try { 20 | const attestation = await this.http.request({ 21 | url: statusUrl, 22 | method: 'GET', 23 | simple: true, 24 | json: true, 25 | }); 26 | 27 | if (!attestation || !attestation.type) { 28 | // eslint-disable-next-line no-unused-vars 29 | return await pollService(statusUrl); 30 | } 31 | if (attestation && attestation.type !== 'permanent') { 32 | attestation.statusUrl = statusUrl; 33 | return attestation; 34 | } 35 | return attestation; 36 | } catch (error) { 37 | logger.error(`Error polling: ${statusUrl}`, JSON.stringify(error, null, 2)); 38 | throw new Error(`Error polling: ${statusUrl}`); 39 | } 40 | }; 41 | 42 | this.anchor = async (options = {}) => ( 43 | Promise.resolve({ 44 | subject: { 45 | pub: 'xpub:dummy', 46 | label: options.subject && options.subject.label ? options.subject.label : null, 47 | data: options.subject && options.subject.data ? options.subject.data : null, 48 | signature: 'signed:dummy', 49 | }, 50 | walletId: 'none', 51 | cosigners: [{ 52 | pub: 'xpub:dummy', 53 | }, { 54 | pub: 'xpub:dummy', 55 | }], 56 | authority: { 57 | pub: 'xpub:dummy', 58 | path: '/', 59 | }, 60 | coin: 'dummycoin', 61 | tx: new uuid(), // eslint-disable-line 62 | network: 'dummynet', 63 | type: 'temporary', 64 | civicAsPrimary: false, 65 | schema: 'dummy-20180201', 66 | }) 67 | ); 68 | 69 | this.update = async (tempAnchor) => { 70 | // eslint-disable-next-line no-param-reassign 71 | tempAnchor.type = 'permanent'; 72 | // eslint-disable-next-line no-param-reassign 73 | tempAnchor.value = uuid(); 74 | return Promise.resolve(tempAnchor); 75 | }; 76 | 77 | this.verifySignature = () => true; 78 | 79 | /** 80 | * This method checks if the subject signature matches the pub key 81 | * @returns {*} true or false for the validation 82 | */ 83 | this.verifySubjectSignature = () => true; 84 | 85 | /** 86 | * This method checks that the attestation / anchor exists on the BC 87 | */ 88 | this.verifyAttestation = async () => true; 89 | 90 | this.revokeAttestation = async (signature) => { 91 | // eslint-disable-next-line no-param-reassign 92 | signature.revoked = true; 93 | return Promise.resolve(signature); 94 | }; 95 | 96 | this.isRevoked = signature => (signature.revoked ? signature.revoked : false); 97 | 98 | return this; 99 | } 100 | 101 | module.exports = { 102 | CurrentCivicAnchor: DummyAnchorServiceImpl, 103 | }; 104 | -------------------------------------------------------------------------------- /src/services/MiniCryptoManagerImpl.js: -------------------------------------------------------------------------------- 1 | const { HDNode, ECSignature } = require('bitcoinjs-lib'); 2 | 3 | /** 4 | * MiniCryptoManagerImpl - A minimal CryptoManagerImpl for the portable CryptoManagerInterface 5 | * to provide only default sign() and verify() functions to credential-commons with minimal dependencies. 6 | * 7 | * Particularities of this Mini Implementation: 8 | * 9 | * 1. Only sign() and verify() function are available; 10 | * 11 | * 2. This implementation is based on HDNode key material from bitcoinjs library; 12 | * 13 | * 3. There is a volatile in memory only Storage Implementation to allow `installKey()`. 14 | * You should `installKey` a PVT key or a PUB key (verify only) before call `sign()` or `verify()`. 15 | * The installed key is removed after `sign()` or `verify()` function was called. 16 | */ 17 | class MiniCryptoManagerImpl { 18 | constructor() { 19 | this.KEY_STORAGE = {}; 20 | } 21 | 22 | /** 23 | * Install a pvt or a pub key on a keyName to be used on `sign()` or `verify()` function later. 24 | * @param {} keyName - name of the key to be installed. 25 | * @param {} key - a pvt or a pub key in base58 format. 26 | */ 27 | installKey(keyName, key) { 28 | try { 29 | // Test if key is a valid HDNode key 30 | HDNode.fromBase58(key); 31 | this.KEY_STORAGE[keyName] = key; 32 | } catch (err) { 33 | throw new Error(`Invalid key format: ${err.message}`); 34 | } 35 | } 36 | 37 | /** 38 | * Return input data signed using the specified key. 39 | * 40 | * Signature return value will be to be a DER encoded value. 41 | * 42 | * @param { string } keyName - name of the key to be used to sign. 43 | * @param { string } hexHash - hex string representation of the hash 44 | */ 45 | sign(keyName, hexHash) { 46 | const privateKey = this.KEY_STORAGE[keyName]; 47 | const keyPair = HDNode.fromBase58(privateKey); 48 | 49 | const hash = Buffer.from(hexHash, 'hex'); 50 | const signature = keyPair.sign(hash); 51 | const hexSignature = signature.toDER().toString('hex'); 52 | 53 | // keys are volatile in this impl, removes 54 | delete this.KEY_STORAGE[keyName]; 55 | 56 | return hexSignature; 57 | } 58 | 59 | /** 60 | * Return true if signature has been verified, false otherwise. 61 | * 62 | * @param { string } keyName - name of the key to be used to verify signature. 63 | * @param { string } hexHash - hex string representation of the hash 64 | * @param { string } hexSignature - DER encoded signature. 65 | */ 66 | verify(keyName, hexHash, hexSignature) { 67 | const key = this.KEY_STORAGE[keyName]; 68 | const keyPair = HDNode.fromBase58(key); 69 | 70 | const hash = Buffer.from(hexHash, 'hex'); 71 | const signature = Buffer.from(hexSignature, 'hex'); 72 | const ecSignature = ECSignature.fromDER(signature); 73 | 74 | // keys are volatile in this impl, removes 75 | delete this.KEY_STORAGE[keyName]; 76 | 77 | return keyPair.verify(hash, ecSignature); 78 | } 79 | } 80 | 81 | module.exports = MiniCryptoManagerImpl; 82 | -------------------------------------------------------------------------------- /src/services/__mocks__/httpService.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | const _ = require('lodash'); 4 | const logger = require('../../logger'); 5 | 6 | function HttpServiceConstructor() { 7 | this.name = 'mockHttp'; 8 | this.request = async (uri, options) => { 9 | logger.debug(`Mocking request for: ${JSON.stringify({ uri, options }, null, 2)}`); 10 | const params = _.isString(uri) ? { url: uri } : uri; 11 | _.assign(params, options); 12 | const responses = [ 13 | { 14 | path: '/registry', 15 | response: { 16 | clientID: '6e0ce9b31eb13064a194c1482ed3d9d330f22df6fb4cbcc0dbebf3169dc2325b', 17 | xpub: '0469919359510a703516503299c77ef0e00f18255a32db19a3e69636e203f25f29be24b685df9f8a70548751f53a2e4c235ec0fbdc82d0783bd30e315ebfd6bd1e', 18 | cas: '{"iv":"TEtgZuJdyJFkgcuHoBC52w==","v":1,"iter":10000,"ks":128,"ts":64,"mode":"gcm","adata":"","cipher":"aes","salt":"SA0z5h6IlfA=","ct":"8h6ys3fD31HsWH3s5rrbF6o54ekJf6owhSJBW6FBIhkftJWSWVWVEt0u0FJFqhCqPaEl+DMM6olH9fAcB7bD7i2DRPjLYiC+"}', 19 | sak: {}, 20 | }, 21 | }, 22 | { 23 | path: '/jwt', 24 | response: { jwt: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiIyYzdlNjQ4YS1hNDhmLTQxNTgtOGZmMS02MTY0YzM5OWNlNDMiLCJpYXQiOjE1Mjg4MjE1ODUuNDM0LCJleHAiOjE1Mjg4MjE3NjUuNDM0LCJpc3MiOiJodHRwczovL2FwaS5jaXZpYy5jb20vand0IiwiYXVkIjoiQXR0ZXN0ZXJTZXJ2aWNlIiwic3ViIjoiYzhhNjRhODE4NWRlMzNkMTlkZTgwMjFmYmUyMjhkMmE1YTc3YzExMTdkYjc1NDJlZDE0ODM1NGNiZjdkNGVmMSIsImRhdGEiOnsibWV0aG9kIjoiUE9TVCIsInBhdGgiOiJodHRwczovL2Rldi5hcGkuY2l2aWMuY29tL3JlcXVlc3QtYXR0ZXN0YXRpb24tdGJjaC9yZXF1ZXN0QXR0ZXN0YXRpb24ifX0.2Rp8XLTLvzu51raTQRpce8kIiilsMeiPZeWAsuNv5n7hFZGl-ce-fx9DgxsZ0OTaIUgo8frbiGmHjQh0WlUG7A' }, 25 | }, 26 | { 27 | path: '/requestAttestation', 28 | response: { statusUrl: '/status/372091f0-6e5f-11e8-ab04-8d6f9c9b4e5a' }, 29 | }, 30 | { 31 | path: '/requestAttestation', 32 | response: { statusUrl: '/status/372091f0-6e5f-11e8-ab04-8d6f9c9b4e5a' }, 33 | }, 34 | { 35 | path: '/status', 36 | response: { 37 | schema: 'dummy-20180201', 38 | tx: '01000000018815822815dbd6c355ad47af5d753a00000000fc00473044022042426820da1f2fac328a408d538638143177168b575da66825bc99a3f487472baa0751b67355407b4a4e99da04a3186c520220578b820dd051c919c2fb57b26aa29667483b547f6766a23e3c821e47a5d1237b0147304402201316cc0ee8a968f4d86a616fcf710b663e0bb7021e95d7a300036b65e95ca34602204f05162db06278af2a8abdd7ab4d92e973dc4154a92bf37a4056f3298fa9ecad014c695221028f9205846d9b23dd9a17588ae13603aa3eda3599582750904716c827d02269db210340f8f56a56b2af2a9698f66574882068cf8bd8fa95a26136ac34edabfe5eb5d021029d52d336232eb3d4f37730822df9d3993a84c3edba20f14d3ee0f20141c0bdfd53aeffffffff01551500000000000017a91460312cbbb8ec560305a239d56398f0d8aa57ecf68700000000', 39 | subject: { 40 | label: 'teste', 41 | pub: 'xpub:dummy', 42 | data: 'testesdsd', 43 | signature: '304502210089e94f11587bf7fa202817ace9664639855a146565d4e54b9f853f31f4d7ce31022077098a904e0dda7ab947db92a3e7dd7a5d52654c286151c3cc97feb0ef4a3310', 44 | }, 45 | authority: { 46 | pub: 'xpub:dummy', 47 | path: '/', 48 | }, 49 | cosigners: [ 50 | { 51 | pub: 'xpub:dummy', 52 | }, 53 | { 54 | pub: 'xpuv:dummy', 55 | }, 56 | ], 57 | type: 'temporary', 58 | network: 'testnet', 59 | }, 60 | 61 | }, 62 | ]; 63 | const res = _.find(responses, r => _.includes(params.url, r.path)); 64 | if (res) { 65 | return Promise.resolve(res.response); 66 | } 67 | return Promise.reject(); 68 | }; 69 | return this; 70 | } 71 | 72 | logger.debug('Using Mock HTTP Service'); 73 | const http = new HttpServiceConstructor(); 74 | http.request('/status').then(console.log); // eslint-disable-line 75 | logger.debug(`HTTP Service instance ${JSON.stringify(http, null, 2)}`); 76 | 77 | module.exports = http; 78 | -------------------------------------------------------------------------------- /src/services/anchorService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Abstract Anchor/Attestation service 3 | * 4 | * @param {*} impl 5 | */ 6 | function Anchor(impl) { 7 | this.impl = impl; 8 | this.anchor = (label, data, options) => this.impl.anchor(label, data, options); 9 | this.update = tempAnchor => this.impl.update(tempAnchor); 10 | this.verifySignature = subject => this.impl.verifySignature(subject); 11 | this.verifySubjectSignature = subject => this.impl.verifySubjectSignature(subject); 12 | this.verifyAttestation = signature => this.impl.verifyAttestation(signature); 13 | this.revokeAttestation = signature => this.impl.revokeAttestation(signature); 14 | this.isRevoked = signature => this.impl.isRevoked(signature); 15 | return this; 16 | } 17 | 18 | module.exports = Anchor; 19 | -------------------------------------------------------------------------------- /src/services/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const os = require('os'); 3 | const fs = require('fs'); 4 | 5 | const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; 6 | 7 | if (process.platform === 'win32') throw new Error(`Unsupported platform: ${process.platform}`); 8 | 9 | if (process.env.APP_ENV !== 'browser' && !isBrowser) { 10 | const CONFIG_FILE = 'config'; 11 | 12 | const CONFIG_PATH = { 13 | BOX: '/etc/civic', 14 | USER: path.join(`${os.homedir()}`, '.civic'), 15 | }; 16 | 17 | const userConfigFile = path.join(CONFIG_PATH.USER, CONFIG_FILE); 18 | const boxConfigFile = path.join(CONFIG_PATH.BOX, CONFIG_FILE); 19 | 20 | const configFile = fs.existsSync(userConfigFile) ? userConfigFile : boxConfigFile; 21 | 22 | /* eslint-disable global-require */ 23 | if (fs.existsSync(userConfigFile)) { 24 | require('dotenv').config({ 25 | path: configFile, 26 | }); 27 | } 28 | /* eslint-ebable global-require */ 29 | } 30 | 31 | const config = { 32 | sipSecurityService: process.env.CIVIC_SEC_URL, 33 | attestationService: process.env.CIVIC_ATTN_URL, 34 | clientConfig: { 35 | id: process.env.CIVIC_CLIENT_ID, 36 | signingKeys: { 37 | hexpub: process.env.CIVIC_CLIENT_XPUB, 38 | hexsec: process.env.CIVIC_CLIENT_XPRV, 39 | }, 40 | }, 41 | passphrase: process.env.CIVIC_PASSPHRASE, 42 | keychain: { prv: process.env.CIVIC_KEYCHAIN }, 43 | accessToken: process.env.CLIENT_ACCESS_TOKEN, 44 | walletId: process.env.CLIENT_WALLET_ID, 45 | walletPassphrase: process.env.CLIENT_WALLET_PASSPHRASE, 46 | }; 47 | 48 | module.exports = config; 49 | -------------------------------------------------------------------------------- /src/services/httpService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple node HTTP services 3 | */ 4 | const request = require('request-promise-native'); 5 | // uncomment to debug requests 6 | // require('request-debug')(request); 7 | 8 | function HttpServiceConstructor() { 9 | this.request = async (uri, options) => { 10 | const response = await request(uri, options); 11 | return response; 12 | }; 13 | return this; 14 | } 15 | 16 | module.exports = HttpServiceConstructor; 17 | -------------------------------------------------------------------------------- /src/services/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Services IoC modules 3 | */ 4 | const Bottle = require('bottlejs'); 5 | const { CurrentCivicAnchor } = require('./DefaultAnchorServiceImpl'); 6 | const logger = require('../logger'); 7 | const HttpServiceConstructor = require('./httpService'); 8 | const config = require('./config'); 9 | const SecureRandom = require('../SecureRandom'); 10 | const MiniCryptoManagerImpl = require('./MiniCryptoManagerImpl'); 11 | 12 | const services = new Bottle(); 13 | 14 | /** 15 | * Init services with new values to config and http services 16 | * @param {*} conf 17 | * @param {*} http 18 | * @param secureRandom 19 | */ 20 | const initServices = (conf, http, secureRandom, cryptoManagerImpl) => { 21 | if (http) { 22 | services.resetProviders(['Http']); 23 | logger.debug('Registering custom HTTP service implementation'); 24 | services.factory('Http', () => http); 25 | } 26 | if (conf) { 27 | services.resetProviders(['Config']); 28 | logger.debug('Registering custom Config service implementation'); 29 | services.factory('Config', () => conf); 30 | } 31 | if (secureRandom) { 32 | services.resetProviders(['SecureRandom']); 33 | logger.debug('Registering custom SecureRandom service implementation'); 34 | services.factory('SecureRandom', () => secureRandom); 35 | } 36 | if (cryptoManagerImpl) { 37 | services.resetProviders(['CryptoManager']); 38 | logger.debug('Registering custom CryptoManager service implementation'); 39 | services.factory('CryptoManager', () => cryptoManagerImpl); 40 | } 41 | return services; 42 | }; 43 | 44 | services.factory('Config', () => config); 45 | 46 | logger.info('Registering request-promise-native as Http service implementation.'); 47 | services.service('Http', HttpServiceConstructor); 48 | 49 | services.factory('SecureRandom', () => new SecureRandom()); 50 | 51 | services.service('AnchorService', CurrentCivicAnchor, 'Config', 'Http'); 52 | 53 | // The default CryptoManager Implementation 54 | services.service('CryptoManager', MiniCryptoManagerImpl); 55 | 56 | module.exports = { services, initServices }; 57 | -------------------------------------------------------------------------------- /src/timeHelper.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment-mini'); 2 | 3 | const unitMapper = { 4 | y: 'y', 5 | m: 'M', 6 | w: 'w', 7 | d: 'd', 8 | }; 9 | 10 | /** 11 | * Convert a delta string like "21y" to a moment Duration object 12 | * @param delta 13 | * @return {moment.Duration} 14 | */ 15 | const timeDeltaToMomentDuration = (delta) => { 16 | const matched = delta.match(/(-?\d+)(\w)/); 17 | 18 | if (!matched) throw new Error(`Invalid time delta ${delta}`); 19 | 20 | const [, amount, unit] = matched; 21 | 22 | return moment.duration(parseInt(amount, 10), unitMapper[unit]); 23 | }; 24 | 25 | /** 26 | * Given a time delta like "-21y", apply it to the passed in date object, or the current time 27 | * @param delta String 28 | * @param date Date 29 | * @return {Date} 30 | */ 31 | const applyDeltaToDate = (delta, date = new Date()) => moment(date) 32 | .add(timeDeltaToMomentDuration(delta)) 33 | .toDate(); 34 | 35 | module.exports = { 36 | applyDeltaToDate, 37 | }; 38 | -------------------------------------------------------------------------------- /src/uca/UCA.js: -------------------------------------------------------------------------------- 1 | const { UserCollectableAttribute: BaseUCA } = require('@identity.com/uca'); 2 | const { schemaLoader } = require('../schemas/jsonSchema'); 3 | 4 | class UserCollectableAttribute extends BaseUCA { 5 | static async create(identifier, value, version) { 6 | await schemaLoader.loadSchemaFromTitle(identifier); 7 | 8 | return new UserCollectableAttribute(identifier, value, version, schemaLoader.ucaDefinitions); 9 | } 10 | } 11 | 12 | module.exports = { UserCollectableAttribute }; 13 | --------------------------------------------------------------------------------