├── source ├── release │ ├── Source code.zip │ └── Source code.tar.gz └── did-fabric-contract │ ├── chaincode │ ├── data │ │ ├── data_type.go │ │ ├── credential_schema.go │ │ ├── provider.go │ │ ├── service.go │ │ ├── vcmeta.go │ │ ├── status.go │ │ ├── verification_method.go │ │ └── document.go │ ├── validate │ │ └── custom_validator.go │ ├── utility │ │ ├── json_util.go │ │ └── crypto.go │ ├── repository │ │ ├── vcmeta_repository.go │ │ └── document_repository.go │ ├── service │ │ ├── vcmeta_service.go │ │ └── document_service.go │ ├── error │ │ └── error.go │ └── opendid.go │ ├── main.go │ ├── go.mod │ ├── README_ko.md │ ├── README.md │ └── go.sum ├── CHANGELOG.md ├── signatures └── version1 │ └── cla.json ├── .gitignore ├── .github ├── pull_request_template.yml ├── workflows │ ├── fabric_contract_ci.yml │ ├── auto_assign.yml │ ├── fabric_contract_release.yml │ └── cla.yml └── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml ├── MAINTAINERS.md ├── dependencies-license.md ├── SECURITY.md ├── README_ko.md ├── README.md ├── RELEASE-PROCESS.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── docs └── api │ └── ContractError.md ├── CLA.md └── LICENSE /source/release/Source code.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OmniOneID/did-fabric-contract/HEAD/source/release/Source code.zip -------------------------------------------------------------------------------- /source/release/Source code.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OmniOneID/did-fabric-contract/HEAD/source/release/Source code.tar.gz -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0.0 (2024-10-18) 4 | 5 | ### 🚀 New Features 6 | 7 | - DID Document transaction management 8 | - VerifiableCredential Metadata transaction management 9 | -------------------------------------------------------------------------------- /signatures/version1/cla.json: -------------------------------------------------------------------------------- 1 | { 2 | "signedContributors": [ 3 | { 4 | "name": "jhkim5981", 5 | "id": 180237641, 6 | "comment_id": 2406640378, 7 | "created_at": "2024-10-11T06:28:52Z", 8 | "repoId": 808509241, 9 | "pullRequestNo": 2 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | go.work.sum 23 | -------------------------------------------------------------------------------- /.github/pull_request_template.yml: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | ## Related Issue (Optional) 5 | 6 | - Issue # (e.g., #123) 7 | 8 | ## Changes 9 | 10 | - Change 1 11 | - Change 2 12 | 13 | ## Screenshots (Optional) 14 | 15 | 16 | ## Additional Comments (Optional) 17 | 18 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | ## Overview 4 | 5 | This file lists the maintainers for this project. Maintainers are responsible for reviewing and merging pull requests, ensuring code quality, and managing releases. 6 | If you have any questions or require support, please reach out to the maintainers listed below. 7 | 8 | 9 | ## Maintainers 10 | | Name | GitHub | email | 11 | |------------------ |-----------------|-------------------------------------| 12 | | Jeongheon Kim | jhkim5981 | jhkim5981@raoncorp.com | 13 | | Minyong Kim | black-billed-magpie | mykim@raoncorp.com | -------------------------------------------------------------------------------- /.github/workflows/fabric_contract_ci.yml: -------------------------------------------------------------------------------- 1 | name: Fabric Contract CI 2 | 3 | on: 4 | push: 5 | branches: [ main, develop ] 6 | pull_request: 7 | branches: [ main, develop ] 8 | 9 | jobs: 10 | fabric-contract-build: 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 60 13 | 14 | defaults: 15 | run: 16 | working-directory: source/did-fabric-contract 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Set up Go 1.22 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: '1.22' 25 | 26 | - name: Install dependencies 27 | run: | 28 | go mod tidy 29 | go mod vendor 30 | 31 | - name: Build the project 32 | run: go build ./... -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/data_type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | type URL string 18 | type Multibase string 19 | type UTCDateTime string 20 | -------------------------------------------------------------------------------- /dependencies-license.md: -------------------------------------------------------------------------------- 1 | # License Information 2 | 3 | ### This project uses the following third-party libraries, each under its own license: 4 | 5 |
6 | 7 | **Btcutil: ISC License** 8 | `github.com/btcsuite/btcutil v1.0.2` 9 | (http://github.com/btcsuite/btcutil) 10 | 11 |
12 | 13 | **CCKit: Apache License 2.0** 14 | `github.com/hyperledger-labs/cckit v1.0.5` 15 | (http://github.com/hyperledger-labs/cckit) 16 | 17 |
18 | 19 | **Fabric Chaincode Go: Apache License 2.0** 20 | `github.com/hyperledger/fabric-chaincode-go v0.0.0-20240704073638-9fb89180dc17` 21 | (http://github.com/hyperledger/fabric-chaincode-go) 22 | 23 |
24 | 25 | **Validator.v9: MIT License** 26 | `gopkg.in/go-playground/validator.v9 v9.31.0` 27 | (https://github.com/go-playground/validator) -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/credential_schema.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | type CREDENTIAL_SCHEMA_TYPE string 18 | 19 | type CredentialSchema struct { 20 | Id URL `validate:"url" json:"id"` 21 | Type CREDENTIAL_SCHEMA_TYPE `validate:"oneof=OsdSchemaCredential" json:"type"` 22 | } 23 | -------------------------------------------------------------------------------- /source/did-fabric-contract/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "did-fabric-contract/chaincode" 19 | "fmt" 20 | 21 | "github.com/hyperledger/fabric-chaincode-go/shim" 22 | ) 23 | 24 | func main() { 25 | if err := shim.Start(chaincode.NewOpenDIDCC()); err != nil { 26 | fmt.Printf("error starting cc : %s", err) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | In this project, the following versions have undergone security vulnerability assessments: 5 | 6 | | Version | Supported | 7 | | ------- | ------------------ | 8 | | 1.0.0 | ✅ | 9 | 10 | ## Reporting a Vulnerability 11 | If you discover a new security vulnerability, please report it via [technology@omnione.net](mailto:technology@omnione.net). 12 | 13 | ## Sensitive Information Protection 14 | Please ensure that sensitive information, such as API keys, passwords, and personal data, is never included in the code or documentation. Such information should be managed outside the code, preferably using environment variables. 15 | 16 | ## Security Policy Configuration 17 | - Vulnerability Management: If a vulnerability is discovered, follow the security reporting procedures and collaborate to apply security patches as quickly as possible. 18 | - Code Review: Any changes related to security must always go through the review process, and multiple contributors should be involved in the review to ensure thorough checks. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report. 3 | title: "[Bug]: " 4 | labels: ["bug", "triage"] 5 | assignees: [""] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this bug report! 11 | - type: textarea 12 | id: what-happened 13 | attributes: 14 | label: What happened? 15 | description: Also tell us, what did you expect to happen? 16 | placeholder: Tell us what you see! 17 | validations: 18 | required: true 19 | - type: input 20 | id: version 21 | attributes: 22 | label: Version 23 | description: What version of our software are you running? 24 | validations: 25 | required: true 26 | - type: textarea 27 | id: logs 28 | attributes: 29 | label: Relevant log output 30 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 31 | render: shell 32 | - type: checkboxes 33 | id: terms 34 | attributes: 35 | label: Code of Conduct 36 | description: By submitting this issue, you agree to follow our [Code of Conduct](../blob/main/CODE_OF_CONDUCT.md). 37 | options: 38 | - label: I agree to follow this project's Code of Conduct 39 | required: true 40 | -------------------------------------------------------------------------------- /source/did-fabric-contract/go.mod: -------------------------------------------------------------------------------- 1 | module did-fabric-contract 2 | 3 | go 1.22 4 | 5 | require ( 6 | github.com/btcsuite/btcutil v1.0.2 7 | github.com/hyperledger-labs/cckit v1.0.5 8 | github.com/hyperledger/fabric-chaincode-go v0.0.0-20240704073638-9fb89180dc17 9 | gopkg.in/go-playground/validator.v9 v9.31.0 10 | ) 11 | 12 | require ( 13 | github.com/go-playground/locales v0.14.1 // indirect 14 | github.com/go-playground/universal-translator v0.18.1 // indirect 15 | github.com/gogo/protobuf v1.3.2 // indirect 16 | github.com/golang/protobuf v1.5.4 // indirect 17 | github.com/hyperledger/fabric-protos-go v0.3.3 // indirect 18 | github.com/leodido/go-urn v1.4.0 // indirect 19 | github.com/mwitkow/go-proto-validators v0.3.2 // indirect 20 | github.com/onsi/ginkgo v1.16.5 // indirect 21 | github.com/onsi/gomega v1.34.2 // indirect 22 | github.com/pkg/errors v0.8.1 // indirect 23 | go.uber.org/atomic v1.6.0 // indirect 24 | go.uber.org/multierr v1.5.0 // indirect 25 | go.uber.org/zap v1.14.1 // indirect 26 | golang.org/x/net v0.28.0 // indirect 27 | golang.org/x/sys v0.24.0 // indirect 28 | golang.org/x/text v0.17.0 // indirect 29 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect 30 | google.golang.org/grpc v1.65.0 // indirect 31 | google.golang.org/protobuf v1.34.1 // indirect 32 | gopkg.in/go-playground/assert.v1 v1.2.1 // indirect 33 | ) 34 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/validate/custom_validator.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package validate 16 | 17 | import ( 18 | "gopkg.in/go-playground/validator.v9" 19 | ) 20 | 21 | func isParentExist(fl validator.FieldLevel) bool { 22 | return !fl.Parent().IsZero() 23 | } 24 | 25 | func optionalRequiredValidator(fl validator.FieldLevel) bool { 26 | if isParentExist(fl) && fl.Field().String() == "" { 27 | return false 28 | } 29 | return true 30 | } 31 | 32 | func RegisterDocumentValidator() *validator.Validate { 33 | v := validator.New() 34 | v.RegisterValidation("optionalRequired", optionalRequiredValidator) 35 | return v 36 | } 37 | 38 | func RegisterVcMetaValidator() *validator.Validate { 39 | v := validator.New() 40 | v.RegisterValidation("optionalRequired", optionalRequiredValidator) 41 | return v 42 | } 43 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/utility/json_util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package utility 16 | 17 | import ( 18 | "encoding/json" 19 | "sort" 20 | ) 21 | 22 | func SortJson(jsonData []byte) []byte { 23 | var jsonMap map[string]interface{} 24 | json.Unmarshal(jsonData, &jsonMap) 25 | 26 | sortedJsonMap := SortJsonKeys(jsonMap) 27 | sortedJsonData, _ := json.Marshal(sortedJsonMap) 28 | return sortedJsonData 29 | } 30 | 31 | func SortJsonKeys(data map[string]interface{}) map[string]interface{} { 32 | sortedMap := make(map[string]interface{}) 33 | keys := make([]string, 0, len(data)) 34 | for k := range data { 35 | keys = append(keys, k) 36 | } 37 | sort.Strings(keys) 38 | for _, k := range keys { 39 | value := data[k] 40 | if nestedMap, ok := value.(map[string]interface{}); ok { 41 | sortedMap[k] = SortJsonKeys(nestedMap) 42 | } else { 43 | sortedMap[k] = value 44 | } 45 | } 46 | return sortedMap 47 | } 48 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/provider.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | const ( 18 | TAS ROLE_TYPE = "Tas" 19 | Wallet ROLE_TYPE = "Wallet" 20 | Issuer ROLE_TYPE = "Issuer" 21 | WalletProvider ROLE_TYPE = "WalletProvider" 22 | AppProvider ROLE_TYPE = "AppProvider" 23 | ListProvider ROLE_TYPE = "ListProvider" 24 | OpProvider ROLE_TYPE = "OpProvider" 25 | KycProvider ROLE_TYPE = "KycProvider" 26 | NotificationProvider ROLE_TYPE = "NotificationProvider" 27 | LogProvider ROLE_TYPE = "LogProvider" 28 | PortalProvider ROLE_TYPE = "PortalProvider" 29 | DelegationProvider ROLE_TYPE = "DelegationProvider" 30 | StorageProvider ROLE_TYPE = "StorageProvider" 31 | BackupProvider ROLE_TYPE = "BackupProvider" 32 | Etc ROLE_TYPE = "Etc" 33 | ) 34 | 35 | type Provider struct { 36 | Did string `validate:"required" json:"did"` 37 | CertVcRef URL `validate:"required,url" json:"certVcRef"` 38 | } 39 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | type DID_SERVICE_TYPE string 18 | type DID_SERVICE_ID string 19 | 20 | const ( 21 | LinkedDomains DID_SERVICE_TYPE = "LinkedDomains" 22 | Credentialregistry DID_SERVICE_TYPE = "Credentialregistry" 23 | ) 24 | 25 | type Service struct { 26 | Id DID_SERVICE_ID `validate:"required" json:"id"` 27 | Type DID_SERVICE_TYPE `validate:"required,oneof=Credentialregistry LinkedDomains" json:"type"` 28 | ServiceEndpoint []URL `validate:"required" json:"serviceEndpoint"` 29 | } 30 | 31 | func (a *Service) IsEqual(b *Service) bool { 32 | if a.Id != b.Id { 33 | return false 34 | } 35 | 36 | if a.Type != b.Type { 37 | return false 38 | } 39 | 40 | if len(a.ServiceEndpoint) != len(b.ServiceEndpoint) { 41 | return false 42 | } 43 | 44 | var baseServiceEndpointLength = len(a.ServiceEndpoint) 45 | for i := 0; i <= baseServiceEndpointLength; i++ { 46 | if a.ServiceEndpoint[i] != b.ServiceEndpoint[i] { 47 | return false 48 | } 49 | } 50 | 51 | return true 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/auto_assign.yml: -------------------------------------------------------------------------------- 1 | name: PR assignment 2 | on: 3 | pull_request_target: 4 | types: [opened, edited, synchronize, reopened, ready_for_review] 5 | 6 | permissions: 7 | contents: read 8 | issues: write 9 | pull-requests: write 10 | 11 | jobs: 12 | auto-assign: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Request Reviewers 16 | uses: actions/github-script@v6 17 | with: 18 | script: | 19 | const author = context.payload.pull_request.user.login; 20 | let reviewers = ['black-billed-magpie','jhkim5981']; 21 | 22 | if (reviewers.includes(author)) { 23 | if(reviewers.length === 1) 24 | reviewers = reviewers.map(reviewer => reviewer === author ? 'mikyung-lee' : reviewer); 25 | else { 26 | reviewers = reviewers.filter(reviewer => reviewer !== author); 27 | } 28 | } 29 | 30 | await github.rest.pulls.requestReviewers({ 31 | owner: context.repo.owner, 32 | repo: context.repo.repo, 33 | pull_number: context.payload.pull_request.number, 34 | reviewers: reviewers 35 | }); 36 | - name: Request Assignees 37 | uses: actions/github-script@v6 38 | with: 39 | script: | 40 | const assignees = ['jhkim5981', 'mikyung-lee']; // assignees 41 | 42 | await github.rest.issues.addAssignees({ 43 | owner: context.repo.owner, 44 | repo: context.repo.repo, 45 | issue_number: context.payload.pull_request.number, 46 | assignees: assignees 47 | }); -------------------------------------------------------------------------------- /.github/workflows/fabric_contract_release.yml: -------------------------------------------------------------------------------- 1 | name: Build and Upload JAR to GitHub Releases 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | types: [closed] 8 | 9 | jobs: 10 | build: 11 | if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/QA-') 12 | runs-on: ubuntu-latest 13 | permissions: 14 | contents: write 15 | pull-requests: write 16 | repository-projects: write 17 | 18 | defaults: 19 | run: 20 | working-directory: source/did-fabric-contract 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Set release title 28 | id: set_release_title 29 | run: | 30 | release_tag=${GITHUB_HEAD_REF#release/QA-} 31 | echo "Release tag: $release_tag" 32 | echo "::set-output name=release_tag::$release_tag" 33 | 34 | - name: Get commit messages 35 | id: get_commit_messages 36 | run: | 37 | commits=$(git log ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} --pretty=format:"* %s") 38 | echo "$commits" > commit_messages.txt 39 | echo "::set-output name=commits::$commits" 40 | 41 | - name: Create GitHub Release 42 | id: create_release 43 | uses: actions/create-release@v1 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | with: 47 | tag_name: ${{ steps.set_release_title.outputs.release_tag }} 48 | release_name: ${{ steps.set_release_title.outputs.release_tag }} 49 | body: | 50 | ## Changes: 51 | ${{ steps.get_commit_messages.outputs.commits }} -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | title: "[Feature]: " 4 | labels: ["enhancement"] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this feature request! 11 | 12 | - type: textarea 13 | id: feature 14 | attributes: 15 | label: Feature Description 16 | description: Please provide a detailed description of the feature. 17 | placeholder: Describe the feature you are requesting. 18 | validations: 19 | required: true 20 | 21 | - type: textarea 22 | id: purpose 23 | attributes: 24 | label: Purpose 25 | description: What is the main purpose of this feature? Why is it needed? 26 | placeholder: Explain the purpose of the feature. 27 | validations: 28 | required: true 29 | 30 | - type: textarea 31 | id: background 32 | attributes: 33 | label: Background 34 | description: Provide any relevant context or background information for this feature. 35 | placeholder: Provide background information. 36 | validations: 37 | required: false 38 | 39 | - type: textarea 40 | id: expected_outcome 41 | attributes: 42 | label: Expected Outcome 43 | description: What are the expected results of implementing this feature? 44 | placeholder: Explain the expected results or impact. 45 | validations: 46 | required: true 47 | 48 | - type: checkboxes 49 | id: terms 50 | attributes: 51 | label: Code of Conduct 52 | description: By submitting this issue, you agree to follow our [Code of Conduct](../blob/main/CODE_OF_CONDUCT.md). 53 | options: 54 | - label: I agree to follow this project's Code of Conduct 55 | required: true -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/vcmeta.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | const ( 18 | VCMETA_PREFIX = "open:vcmeta:" 19 | ) 20 | 21 | type VC_STATUS string 22 | 23 | const ( 24 | VC_ACTIVE VC_STATUS = "ACTIVE" 25 | VC_INACTIVE VC_STATUS = "INACTIVE" 26 | VC_REVOKED VC_STATUS = "REVOKED" 27 | ) 28 | 29 | type VcMeta struct { 30 | Id string `validate:"required" json:"id"` 31 | Issuer Provider `validate:"required" json:"issuer"` 32 | Subject string `validate:"required" json:"subject"` 33 | CredentialSchema CredentialSchema `validate:"required" json:"credentialSchema"` 34 | Status VC_STATUS `validate:"required" json:"status"` 35 | IssuanceDate string `validate:"required" json:"issuanceDate"` 36 | ValidFrom string `validate:"required" json:"validFrom"` 37 | ValidUntil string `validate:"required" json:"validUntil"` 38 | FormatVersion string `validate:"required" json:"formatVersion"` 39 | Language string `validate:"required" json:"language"` 40 | } 41 | 42 | func (v VcMeta) Key() ([]string, error) { 43 | return []string{VCMETA_PREFIX, v.Id}, nil 44 | } 45 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/status.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | type DIDDOC_STATUS string 22 | type ROLE_TYPE string 23 | 24 | const ( 25 | DOC_ACTIVATED DIDDOC_STATUS = "ACTIVATED" 26 | DOC_DEACTIVATED DIDDOC_STATUS = "DEACTIVATED" 27 | DOC_REVOKED DIDDOC_STATUS = "REVOKED" 28 | DOC_TERMINATED DIDDOC_STATUS = "TERMINATED" 29 | 30 | DIDDOC_STATUS_PREFIX = "open:did:status:" 31 | ) 32 | 33 | type DocumentStatus struct { 34 | Id string `json:"did"` 35 | Status DIDDOC_STATUS `json:"status"` 36 | Version string `json:"version"` 37 | Type ROLE_TYPE `json:"type"` 38 | TerminatedTime UTCDateTime `json:"cancelled_time,omitempty"` 39 | } 40 | 41 | func (s *DocumentStatus) Key() ([]string, error) { 42 | return []string{DIDDOC_STATUS_PREFIX, s.Id}, nil 43 | } 44 | 45 | func (s *DocumentStatus) Revoke() error { 46 | if s.Status == DOC_ACTIVATED || s.Status == DOC_DEACTIVATED { 47 | s.Status = DOC_REVOKED 48 | return nil 49 | } 50 | return fmt.Errorf("cannot update status from %s to %s", s.Status, DOC_REVOKED) 51 | } 52 | 53 | func (s *DocumentStatus) Terminated(terminatedTime UTCDateTime) error { 54 | if s.Status == DOC_REVOKED { 55 | s.Status = DOC_TERMINATED 56 | s.TerminatedTime = terminatedTime 57 | return nil 58 | } 59 | return fmt.Errorf("cannot update status from %s to %s", s.Status, DOC_TERMINATED) 60 | } 61 | 62 | func MakeDocumentStatus(didDoc *DidDoc, roleType ROLE_TYPE) *DocumentStatus { 63 | return &DocumentStatus{ 64 | Id: didDoc.Id, 65 | Status: DOC_ACTIVATED, 66 | Version: didDoc.VersionId, 67 | Type: roleType, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /README_ko.md: -------------------------------------------------------------------------------- 1 | # Fabric Contract 2 | Fabric Contract Repository에 오신 것을 환영합니다. 3 | 이 리포지토리는 Hyperledger Fabric 블록체인에서 스마트 계약을 개발하고 관리하기 위한 도구와 리소스를 제공합니다. 4 | 5 | ## 폴더 구조 6 | ``` 7 | did-fabric-contract 8 | ├── CHANGELOG.md 9 | ├── CLA.md 10 | ├── CODE_OF_CONDUCT.md 11 | ├── CONTRIBUTING.md 12 | ├── LICENSE 13 | ├── dependencies-license.md 14 | ├── MAINTAINERS.md 15 | ├── README.md 16 | ├── README_ko.md 17 | ├── RELEASE-PROCESS.md 18 | ├── SECURITY.md 19 | ├── docs 20 | │ └── api 21 | │ └── ContractError.md 22 | └── source 23 | ├── did-fabric-contract 24 | │ ├── README.md 25 | │ ├── README_ko.md 26 | │ ├── chaincode 27 | │ ├── go.mod 28 | │ ├── go.sum 29 | │ └── main.go 30 | └── release 31 | ├── Source code.tar.gz 32 | └── Source code.zip 33 | ``` 34 | 35 | | 이름 | 역할 | 36 | | -------------------------- | ------------------------------------------ | 37 | | CHANGELOG.md | 프로젝트 버전별 변경사항 | 38 | | CLA.md | Contributor License Agreement | 39 | | CODE_OF_CONDUCT.md | 기여자의 행동강령 | 40 | | CONTRIBUTING.md | 기여 절차 및 방법 | 41 | | LICENSE | Apache 2.0 | 42 | | dependencies-license.md | 프로젝트 의존성 라이브러리에 대한 라이선스 | 43 | | MAINTAINERS.md | 유지관리 가이드 | 44 | | README.md | 프로젝트의 전체적인 개요 설명 | 45 | | RELEASE-PROCESS.md | 릴리즈 절차 | 46 | | SECURITY.md | 보안취약점 보고 및 보안정책 | 47 | | docs | 문서 | 48 | | ┖ api | API 가이드 문서 | 49 | | source | Chaincode 소스코드 프로젝트 | 50 | 51 | ## 릴리즈 52 | 릴리즈는 [Releases](https://github.com/OmniOneID/did-fabric-contract/releases)에서 찾을 수 있습니다. 53 | 54 | ## Change Log 55 | Change Log에는 버전별 변경 사항과 업데이트가 자세히 기록되어 있습니다. 다음에서 확인할 수 있습니다: 56 | - [Change Log](./CHANGELOG.md) 57 | 58 | ## 데모 영상
59 | OpenDID 시스템의 실제 동작을 보여주는 데모 영상은 [Demo Repository](https://github.com/OmniOneID/did-demo-server)에서 확인하실 수 있습니다.
60 | 사용자 등록, VC 발급, VP 제출 등 주요 기능들을 영상으로 확인하실 수 있습니다. 61 | 62 | ## 기여 63 | Contributing 및 pull request 제출 절차에 대한 자세한 내용은 [CONTRIBUTING.md](CONTRIBUTING.md)와 [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) 를 참조하세요. 64 | 65 | ## 라이선스 66 | [Apache 2.0](LICENSE) -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/verification_method.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | import ( 18 | "bytes" 19 | "crypto/sha256" 20 | "encoding/json" 21 | "fmt" 22 | ) 23 | 24 | type AUTH_TYPE int 25 | 26 | const ( 27 | Free AUTH_TYPE = 1 28 | PIN AUTH_TYPE = 2 29 | BIO AUTH_TYPE = 4 30 | ) 31 | 32 | const ( 33 | RSA KEY_TYPE = "RsaVerificationKey2018" 34 | K1 KEY_TYPE = "Secp256k1VerificationKey2018" 35 | R1 KEY_TYPE = "Secp256r1VerificationKey2018" 36 | ) 37 | 38 | type VerificationMethod struct { 39 | Id DID_KEY_ID `validate:"required" json:"id"` 40 | Type KEY_TYPE `validate:"required" json:"type"` 41 | Controller string `validate:"required" json:"controller"` 42 | PublicKeyMultibase Multibase `validate:"required" json:"publicKeyMultibase"` 43 | AuthType AUTH_TYPE `validate:"required" json:"authType"` 44 | } 45 | 46 | func (a *VerificationMethod) IsEqual(b *VerificationMethod) (bool, error) { 47 | hashData, err := a.ToHash() 48 | if err != nil { 49 | return false, fmt.Errorf("failed to hash the first verificationMethod : %w", err) 50 | } 51 | 52 | comparedHashData, err := b.ToHash() 53 | if err != nil { 54 | return false, fmt.Errorf("failed to hash the second verificationMethod : %w", err) 55 | } 56 | 57 | return bytes.Equal(hashData, comparedHashData), nil 58 | } 59 | 60 | func (v *VerificationMethod) ToJson() ([]byte, error) { 61 | jsonData, err := json.Marshal(v) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | return jsonData, nil 67 | } 68 | 69 | func (v *VerificationMethod) ToObject(data []byte) error { 70 | return json.Unmarshal(data, v) 71 | } 72 | 73 | func (v *VerificationMethod) ToHash() ([]byte, error) { 74 | hash := sha256.New() 75 | 76 | jsonData, err := v.ToJson() 77 | if err != nil { 78 | return nil, err 79 | } 80 | 81 | hash.Write(jsonData) 82 | md := hash.Sum(nil) 83 | 84 | return md, nil 85 | } 86 | -------------------------------------------------------------------------------- /.github/workflows/cla.yml: -------------------------------------------------------------------------------- 1 | name: "CLA Assistant" 2 | on: 3 | issue_comment: 4 | types: [created] 5 | pull_request_target: 6 | types: [opened,closed,synchronize] 7 | 8 | # explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings 9 | permissions: 10 | actions: write 11 | contents: write # this can be 'read' if the signatures are in remote repository 12 | pull-requests: write 13 | statuses: write 14 | 15 | jobs: 16 | CLAAssistant: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: "CLA Assistant" 20 | if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' 21 | uses: contributor-assistant/github-action@v2.6.1 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | # the below token should have repo scope and must be manually added by you in the repository's secret 25 | # This token is required only if you have configured to store the signatures in a remote repository/organization 26 | # PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 27 | with: 28 | path-to-signatures: 'signatures/version1/cla.json' 29 | path-to-document: 'https://github.com/OmniOneID/did-fabric-contract/blob/main/CLA.md' # e.g. a CLA document 30 | # branch should not be protected 31 | branch: 'main' 32 | allowlist: user1,bot* 33 | 34 | # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken 35 | #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) 36 | #remote-repository-name: enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository) 37 | #create-file-commit-message: 'For example: Creating file for storing CLA Signatures' 38 | #signed-commit-message: 'For example: $contributorName has signed the CLA in $owner/$repo#$pullRequestNo' 39 | #custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign' 40 | #custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA' 41 | #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.' 42 | #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) 43 | #use-dco-flag: true - If you are using DCO instead of CLA 44 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/repository/vcmeta_repository.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package repository 16 | 17 | import ( 18 | "did-fabric-contract/chaincode/data" 19 | . "did-fabric-contract/chaincode/error" 20 | "encoding/json" 21 | 22 | "github.com/hyperledger-labs/cckit/router" 23 | ) 24 | 25 | // InsertVcMeta 26 | /* 27 | The function inserts the provided VC metadata into the ledger. 28 | 29 | * @param ctx The router context used for state management. 30 | * @param vcMeta The VC metadata to be inserted into the ledger. 31 | 32 | * @return An error if the insertion fails, otherwise nil. 33 | */ 34 | func InsertVcMeta(ctx router.Context, vcMeta *data.VcMeta) error { 35 | if err := ctx.State().Insert(vcMeta); err != nil { 36 | return GetContractError(VCMETA_INSERT_ERROR, err) 37 | } 38 | return nil 39 | } 40 | 41 | // PutVcMeta 42 | /* 43 | The function updates or inserts the VC metadata in the ledger. If the VC metadata already exists, it is updated; otherwise, it is inserted. 44 | 45 | * @param ctx The router context used for state management. 46 | * @param vcMeta The VC metadata to be updated or inserted into the ledger. 47 | 48 | * @return An error if the update or insertion fails, otherwise nil. 49 | */ 50 | func PutVcMeta(ctx router.Context, vcMeta *data.VcMeta) error { 51 | if err := ctx.State().Put(vcMeta); err != nil { 52 | return GetContractError(VCMETA_PUT_ERROR, err) 53 | } 54 | return nil 55 | } 56 | 57 | // GetVcMeta 58 | /* 59 | The function retrieves the VC metadata for the specified VC ID from the ledger. 60 | 61 | * @param ctx The router context used for state management. 62 | * @param vcId The VC ID of the VC metadata to retrieve. 63 | 64 | * @return The VC metadata associated with the specified VC ID if found. 65 | * @return An error if the retrieval fails or if there is an issue converting the data. 66 | */ 67 | func GetVcMeta(ctx router.Context, vcId string) (*data.VcMeta, error) { 68 | result, err := ctx.State().Get(&data.VcMeta{Id: vcId}) 69 | var vcMeta *data.VcMeta 70 | if err != nil { 71 | return nil, GetContractError(VCMETA_GET_ERROR, err) 72 | } 73 | if err = json.Unmarshal(result.([]uint8), &vcMeta); err != nil { 74 | return nil, GetContractError(VCMETA_CONVERT_ERROR, err) 75 | } 76 | return vcMeta, nil 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fabric Contract 2 | Welcome to the Fabric Contract Repository. 3 | This repository provides resources for developing and managing smart contracts on the Hyperledger Fabric blockchain. 4 | 5 | ## Folder Structure 6 | ``` 7 | did-fabric-contract 8 | ├── CHANGELOG.md 9 | ├── CLA.md 10 | ├── CODE_OF_CONDUCT.md 11 | ├── CONTRIBUTING.md 12 | ├── LICENSE 13 | ├── dependencies-license.md 14 | ├── MAINTAINERS.md 15 | ├── README.md 16 | ├── README_ko.md 17 | ├── RELEASE-PROCESS.md 18 | ├── SECURITY.md 19 | ├── docs 20 | │ └── api 21 | │ └── ContractError.md 22 | └── source 23 | ├── did-fabric-contract 24 | │ ├── README.md 25 | │ ├── README_ko.md 26 | │ ├── chaincode 27 | │ ├── go.mod 28 | │ ├── go.sum 29 | │ └── main.go 30 | └── release 31 | ├── Source code.tar.gz 32 | └── Source code.zip 33 | ``` 34 | 35 | | Name | Description | 36 | | ----------------------- | ----------------------------------------------- | 37 | | CHANGELOG.md | Version-specific changes in the project | 38 | | CLA.md | Contributor License Agreement | 39 | | CODE_OF_CONDUCT.md | Code of conduct for contributors | 40 | | CONTRIBUTING.md | Contribution guidelines and procedures | 41 | | LICENSE | Apache 2.0 | 42 | | dependencies-license.md | Licenses for the project’s dependency libraries | 43 | | MAINTAINERS.md | General guidelines for maintaining | 44 | | README.md | Overview and description of the project | 45 | | RELEASE-PROCESS.md | Release process | 46 | | SECURITY.md | Security policies and vulnerability reporting | 47 | | docs | Documentation | 48 | | ┖ api | API guide documentation | 49 | | source | Chaincode source code project | 50 | 51 | 52 | ## Releases 53 | Releases can be found in the [Releases](https://github.com/OmniOneID/did-fabric-contract/releases). 54 | 55 | ## Change Log 56 | The Change Log provides a detailed record of version-specific changes and updates. You can find it here: 57 | - [Change Log](./CHANGELOG.md) 58 | 59 | ## OpenDID Demonstration Videos
60 | To watch our demonstration videos of the OpenDID system in action, please visit our [Demo Repository](https://github.com/OmniOneID/did-demo-server).
61 | These videos showcase key features including user registration, VC issuance, and VP submission processes. 62 | 63 | ## Contributing 64 | 65 | Please read [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for details on our code of conduct, and the process for submitting pull requests to us. 66 | 67 | 68 | ## License 69 | [Apache 2.0](LICENSE) -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/service/vcmeta_service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package service 16 | 17 | import ( 18 | "did-fabric-contract/chaincode/data" 19 | . "did-fabric-contract/chaincode/error" 20 | "did-fabric-contract/chaincode/repository" 21 | "did-fabric-contract/chaincode/validate" 22 | "fmt" 23 | "strings" 24 | 25 | "github.com/hyperledger-labs/cckit/state" 26 | 27 | "github.com/hyperledger-labs/cckit/router" 28 | ) 29 | 30 | // RegisterVcMetadata 31 | /* 32 | The function registers the provided VC metadata into the ledger after validating it. 33 | 34 | * @param ctx The router context used for state management. 35 | * @param vcMeta The VC metadata to be registered in the ledger. 36 | 37 | * @return An error if any issue occurred during validation or insertion, otherwise nil. 38 | */ 39 | func RegisterVcMetadata(ctx router.Context, vcMeta data.VcMeta) error { 40 | v := validate.RegisterVcMetaValidator() 41 | if err := v.Struct(vcMeta); err != nil { 42 | return GetContractError(VCMETA_CONVERT_ERROR, err) 43 | } 44 | 45 | if err := repository.InsertVcMeta(ctx, &vcMeta); err != nil { 46 | return err 47 | } 48 | return nil 49 | } 50 | 51 | // GetVcMetadata 52 | /* 53 | The function retrieves the VC metadata for the specified VC ID from the ledger. 54 | 55 | * @param ctx The router context used for state management. 56 | * @param vcId The VC ID of the VC metadata to retrieve. 57 | 58 | * @return The VC metadata associated with the specified VC ID if found. 59 | * @return An error if any issue occurred during retrieval or if the key is not found. 60 | */ 61 | func GetVcMetadata(ctx router.Context, vcId string) (*data.VcMeta, error) { 62 | vcMeta, err := repository.GetVcMeta(ctx, vcId) 63 | if err != nil && !strings.Contains(err.Error(), state.ErrKeyNotFound.Error()) { 64 | return nil, err 65 | } 66 | return vcMeta, nil 67 | } 68 | 69 | // UpdateVcStatus 70 | /* 71 | The function updates the status of the VC metadata associated with the specified VC ID. 72 | 73 | * @param ctx The router context used for state management. 74 | * @param vcId The VC ID of the VC metadata to update. 75 | * @param vcStatus The new status to set for the VC metadata. 76 | 77 | * @return An error if any issue occurred during retrieval or update, or if the status update is invalid. 78 | */ 79 | func UpdateVcStatus(ctx router.Context, vcId string, vcStatus data.VC_STATUS) error { 80 | vcMeta, err := repository.GetVcMeta(ctx, vcId) 81 | if err != nil { 82 | return err 83 | } 84 | if vcMeta.Status == vcStatus || vcMeta.Status == data.VC_REVOKED { 85 | return GetContractError(VCMETA_STATUS_INVALID, fmt.Errorf("cannot update status from %s to %s", vcMeta.Status, vcStatus)) 86 | } 87 | vcMeta.Status = vcStatus 88 | if err := repository.PutVcMeta(ctx, vcMeta); err != nil { 89 | return err 90 | } 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/error/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package error 16 | 17 | const ( 18 | // Prefix code used for error codes. 19 | PREFIX_CODE = "SSRVFCC" 20 | 21 | // DID Document error codes. 22 | DIDDOC_INSERT_ERROR = "01001" 23 | DIDDOC_GET_ERROR = "01002" 24 | DIDDOC_PUT_ERROR = "01003" 25 | DIDDOC_PROVIDER_INVALID = "01004" 26 | DIDDOC_CONVERT_ERROR = "01005" 27 | DIDDOC_SIGNATURE_VERIFICATION_ERROR = "01006" 28 | DID_KEY_URL_PARSING_ERROR = "01007" 29 | DIDDOC_VERSIONID_INVAILD = "01008" 30 | 31 | // DID Document Status error codes. 32 | DIDDOC_STATUS_INSERT_ERROR = "02001" 33 | DIDDOC_STATUS_GET_ERROR = "02002" 34 | DIDDOC_STATUS_PUT_ERROR = "02003" 35 | DIDDOC_STATUS_CONVERT_ERROR = "02004" 36 | DIDDOC_STATUS_INVALID = "02005" 37 | 38 | // VC Meta error codes. 39 | VCMETA_INSERT_ERROR = "03001" 40 | VCMETA_GET_ERROR = "03002" 41 | VCMETA_PUT_ERROR = "03003" 42 | VCMETA_CONVERT_ERROR = "03004" 43 | VCMETA_STATUS_INVALID = "03005" 44 | ) 45 | 46 | // Mapping of error codes to error messages. 47 | var errMsg = map[string]string{ 48 | DIDDOC_INSERT_ERROR: "Failed to insert did document", 49 | DIDDOC_GET_ERROR: "Failed to get did document", 50 | DIDDOC_PUT_ERROR: "Failed to update did document", 51 | DIDDOC_PROVIDER_INVALID: "Provider is invalid", 52 | DIDDOC_CONVERT_ERROR: "Failed to convert json data to did document", 53 | DIDDOC_SIGNATURE_VERIFICATION_ERROR: "Failed to signature verification", 54 | DID_KEY_URL_PARSING_ERROR: "VerificationMethod is invalid", 55 | DIDDOC_VERSIONID_INVAILD: "VersionId is inavlid", 56 | 57 | DIDDOC_STATUS_INSERT_ERROR: "Failed to insert did document status", 58 | DIDDOC_STATUS_GET_ERROR: "Failed to get did document status", 59 | DIDDOC_STATUS_PUT_ERROR: "Failed to update did document status", 60 | DIDDOC_STATUS_CONVERT_ERROR: "Failed to convert json data to did document status", 61 | DIDDOC_STATUS_INVALID: "Did document status is invalid", 62 | 63 | VCMETA_INSERT_ERROR: "Failed to insert vc meta", 64 | VCMETA_GET_ERROR: "Failed to get vc meta", 65 | VCMETA_PUT_ERROR: "Failed to update vc meta", 66 | VCMETA_CONVERT_ERROR: "Failed to convert json data to vc meta", 67 | VCMETA_STATUS_INVALID: "Vc meta status is invalid", 68 | } 69 | 70 | type ContractError struct { 71 | Code string 72 | Message string 73 | } 74 | 75 | func (c *ContractError) Error() string { 76 | return "ErrorCode : " + c.Code + ", Message : " + c.Message 77 | } 78 | 79 | func GetContractError(code string, err error) *ContractError { 80 | 81 | return &ContractError{ 82 | Code: PREFIX_CODE + code, 83 | Message: errMsg[code] + " => " + err.Error(), 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /RELEASE-PROCESS.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | This document describes the Release Process for QA validation and deployment of feature additions and modifications for each repository. It covers version management and QA validation procedures for each module, as well as the process for managing the integrated Release of all modules. 4 | 5 | ## 1. Versioning 6 | 7 | The project follows a versioning rule in the format "X.Y.Z" where: 8 | - X (Major): Significant changes that are not backward compatible 9 | - Y (Minor): New features that are backward compatible 10 | - Z (Patch): Bug fixes or minor improvements that are backward compatible 11 | 12 | > When the Major version is updated, both Minor and Patch are reset to 0. 13 | >
14 | > When the Minor version is updated, the Patch is reset to 0. 15 | 16 | The integrated module version follows a four-digit format "W.X.Y.Z" assigned after QA approval. 17 | 18 | - W.X: Official product number 19 | - Y: Release 20 | - Z: Bug fix 21 | 22 | ## 2. Release Procedure for Each Repository 23 | 24 | Each module (repository) is managed independently, following these steps: 25 | 26 | 1. **Change Log Review** 27 | Review the [CHANGE LOG](CHANGELOG.md) for each module to ensure all changes are recorded. 28 | 29 | 2. **Create a Release Branch** 30 | If there are changes or modifications, create a branch "release/QA-VX.Y.Z" for QA validation. 31 | - Example: If there are bug fixes or minor improvements for V1.0.0, create a branch "release/QA-V1.0.1". 32 | 33 | For modules without changes, use the existing version (V1.0.0) and the already distributed JAR or library. 34 | 35 | 3. **QA Validation** 36 | - Perform QA validation on the Release branch, addressing any issues identified during the process. 37 | - Approve the Release once QA validation is complete. 38 | 39 | 4. **Merge into Main and Develop Branches** 40 | - Merge the validated Release branch (release/QA-VX.Y.Z) into both `main` and `develop` branches. 41 | 42 | 5. **Create a Release for Each Repository** 43 | - When the validated branch is merged into `main`, trigger the [CI/CD pipeline](https://github.com/OmniOneID/did-release/blob/main/docs/CI_CD_PIPELINE.md) using GitHub Actions to create the Release and perform version tagging. The generated [Release](https://github.com/OmniOneID/did-fabric-contract/releases) includes the following: 44 | - Version name 45 | - Summary of the changelog 46 | - Source code archive 47 | - Distributed files 48 | - Delete the release/QA-VX.Y.Z branch after the release. 49 | 50 | ## 3. Integrated Release Management (did-release Repository) 51 | 52 | After QA approval, manage the complete version control of all modules in a separate repository called [did-release](https://github.com/OmniOneID/did-release/). 53 | 54 | 1. **Managing QA Request Branches** 55 | - Create a directory for the QA request version (format: W.X.Y.Z, e.g., V1.0.1.0). The directory name should be /release-VW.X.Y.Z (e.g., /release-V1.0.1.0). 56 | - Gather the version names of the branches created for QA validation (release/QA-VX.Y.Z) and document version information and modifications in a table within the directory. Name the file 'QA-PLAN-VW.X.Y.Z.md' and register it in the issue menu of the `did-release` repository. 57 | - Include versions of unchanged modules as well. 58 | 59 | 2. **Individual Releases After QA Approval** 60 | - Once all modules have passed QA validation, and their respective `release/QA-VX.Y.Z` branches are merged into `main` and `develop`, create releases for each repository. 61 | 62 | 3. **Publishing the Integrated Release** 63 | - After all modules are approved and released, manage the integrated Release in the `did-release` repository. 64 | - Retrieve the latest version tags for each module and post them in the Release menu of the `did-release`. 65 | - Document the release information in a file named release-VW.X.Y.Z.md within the previously created directory. 66 | 67 | - Example: 68 | 69 | ## Release Note V1.0.1.0 70 | 71 | | Repository | Version | Changelog | Release | 72 | | ------------------ | --------------- | --------------------------- | --------------------------- | 73 | | did-fabric-contract | V1.0.1 | [Changelog](https://github.com/OmniOneID/did-fabric-contract/blob/main/CHANGELOG.md) | 74 | | .. | .. | .. | 75 | 76 |
77 | 78 | ## 4. Automating Integrated Release Script 79 | 80 | Use GitHub Actions or Shell scripts to automate the following tasks: 81 | - Retrieve the release tag information for each module and publish the integrated Release. 82 | - Once all module releases are completed, gather the latest Release information for each module and publish the final version in the `did-release` repository to manage the overall project release. 83 | - The integrated release version follows the "W.X.Y.Z" format, based on the most significant changes. 84 | 85 | This process enables efficient management of individual module versions and the overall integrated project release. 86 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/data/document.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package data 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | type DID_KEY_ID string 22 | type KEY_TYPE string 23 | type VersionID string 24 | type PROOF_PURPOSE string 25 | type DID_KEY_URL string 26 | 27 | const ( 28 | DIDDOC_PREFIX = "open:did:doc:" 29 | LATEST = ":latest" 30 | ) 31 | 32 | const ( 33 | RSASignature KEY_TYPE = "RsaSignature2018" 34 | Secp256k1 KEY_TYPE = "Secp256k1Signature2018" 35 | Secp256r1 KEY_TYPE = "Secp256r1Signature2018" 36 | ) 37 | 38 | const ( 39 | AssertionMethod PROOF_PURPOSE = "assertionMethod" 40 | Authentication PROOF_PURPOSE = "authentication" 41 | KeyAgreement PROOF_PURPOSE = "keyAgreement" 42 | CapabilityInvocation PROOF_PURPOSE = "capabilityInvocation" 43 | CapabilityDelegation PROOF_PURPOSE = "capabilityDelegation" 44 | ) 45 | 46 | type DidDoc struct { 47 | Context []URL `validate:"required" json:"@context"` 48 | Id string `validate:"required" json:"id"` 49 | Controller string `validate:"required" json:"controller"` 50 | Created UTCDateTime `validate:"required" json:"created"` 51 | Updated UTCDateTime `validate:"required" json:"updated"` 52 | VersionId string `validate:"required" json:"versionId"` 53 | Deactivated bool `json:"deactivated"` 54 | VerificationMethod []VerificationMethod `validate:"required" json:"verificationMethod"` 55 | AssertionMethod []DID_KEY_ID `json:"assertionMethod,omitempty"` 56 | Authentication []DID_KEY_ID `json:"authentication,omitempty"` 57 | KeyAgreement []DID_KEY_ID `json:"keyAgreement,omitempty"` 58 | CapabilityInvocation []DID_KEY_ID `json:"capabilityInvocation,omitempty"` 59 | CapabilityDelegation []DID_KEY_ID `json:"capabilityDelegation,omitempty"` 60 | Service []Service `json:"service,omitempty"` 61 | } 62 | 63 | type DidDocWithVersionId struct { 64 | DidDoc 65 | } 66 | 67 | type InvokedDidDoc struct { 68 | DidDoc Multibase `json:"didDoc"` 69 | Proof InvokeProof `json:"proof"` 70 | Controller Provider `json:"controller"` 71 | Nonce Multibase `json:"nonce"` 72 | } 73 | 74 | type DidDocAndStatus struct { 75 | DidDoc DidDoc `json:"document"` 76 | Status DIDDOC_STATUS `json:"status"` 77 | } 78 | 79 | type InvokeProof struct { 80 | Type KEY_TYPE `json:"type"` 81 | Created UTCDateTime `json:"created"` 82 | VerificationMethod DID_KEY_URL `json:"verificationMethod"` 83 | ProofPurpose PROOF_PURPOSE `json:"proofPurpose"` 84 | ProofValue Multibase `json:"proofValue,omitempty"` 85 | } 86 | 87 | func (d *DidDoc) GetVerificationMethod(id string) (*VerificationMethod, error) { 88 | if !d.isCapabilityInvocation(DID_KEY_ID(id)) { 89 | return nil, fmt.Errorf("cannot found key in capabilityInvocation") 90 | } 91 | 92 | for i := 0; i < len(d.VerificationMethod); i++ { 93 | if d.VerificationMethod[i].Id == DID_KEY_ID(id) { 94 | return &d.VerificationMethod[i], nil 95 | } 96 | } 97 | 98 | return nil, fmt.Errorf("cannot found key in verificationMethod") 99 | } 100 | 101 | func (d *DidDoc) isCapabilityInvocation(id DID_KEY_ID) bool { 102 | for i := 0; i < len(d.CapabilityInvocation); i++ { 103 | if d.CapabilityInvocation[i] == DID_KEY_ID(id) { 104 | return true 105 | } 106 | } 107 | return false 108 | } 109 | 110 | func (d *DidDoc) SwitchStatus(status DIDDOC_STATUS) error { 111 | switch status { 112 | case DOC_ACTIVATED: 113 | d.Deactivated = false 114 | return nil 115 | case DOC_DEACTIVATED: 116 | d.Deactivated = true 117 | return nil 118 | default: 119 | return fmt.Errorf("unsupported status: %s", status) 120 | } 121 | } 122 | 123 | func (d DidDoc) Key() ([]string, error) { 124 | return []string{DIDDOC_PREFIX, d.Id, LATEST}, nil 125 | } 126 | 127 | func (d DidDocWithVersionId) Key() ([]string, error) { 128 | return []string{DIDDOC_PREFIX, d.Id, ":versionId:" + d.VersionId}, nil 129 | } 130 | 131 | func MakeDidDocWithVersionId(didDoc *DidDoc) *DidDocWithVersionId { 132 | return &DidDocWithVersionId{ 133 | DidDoc: *didDoc, 134 | } 135 | } 136 | 137 | func MakeDidDocAndStatus(didDoc *DidDoc, status DIDDOC_STATUS) *DidDocAndStatus { 138 | return &DidDocAndStatus{ 139 | DidDoc: *didDoc, 140 | Status: status, 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /source/did-fabric-contract/README_ko.md: -------------------------------------------------------------------------------- 1 | # Fabric Contract Guide 2 | 본 문서는 OpenDID Chaincode 사용을 위한 가이드로, 3 | Open DID에 필요한 DID Document(DID 문서), Verifiable Credential Metadata(이하 VC Meta) 정보를 블록체인에 저장하고 관리하는 기능을 제공합니다. Chaincode는 Blockchain SDK로부터 받은 요청을 처리하여 트랜잭션을 생성 및 기록합니다. 4 | 5 | ## S/W 사양 6 | | 구분 | 내용 | 7 | |------|----------------------------| 8 | | Language | Golang 1.22 | 9 | 10 |
11 | 12 | ## 체인코드 기능 13 | OpenDID Chaincode는 DID 문서 및 VC Meta 데이터와 관련된 트랜잭션 처리 기능을 제공합니다. 라우팅 함수 `NewOpenDIDCC`를 통해 호출하는 함수명과 기능은 다음과 같습니다: 14 | 15 | * document_registerDidDoc: 새로운 DID 문서를 등록/변경하고 상태를 저장합니다. 16 | * document_getDidDoc: 특정 DID 문서와 해당 DID 문서 상태를 조회합니다. 17 | * document_updateDidDocStatusInService: In-Service 간 DID 문서 상태를 변경합니다. 18 | * document_updateDidDocStatusRevocation: DID 문서를 Revocation 상태로 변경합니다. 19 | * vcMeta_registerVcMetadata: VC 메타데이터를 등록합니다. 20 | * vcMeta_getVcMetadata: 특정 VC 메타데이터를 조회합니다. 21 | * vcMeta_updateVcStatus: VC 메타데이터의 상태를 변경합니다. 22 | 23 |
24 | 25 | ## 설치 및 배포 26 | Hyperledger Fabric에서 제공하는 test-network를 사용하여 손쉽게 Fabric 네트워크를 구축할 수 있습니다.
27 | 아래 단계에서 안내하고 있는 네트워크 실행 및 체인코드 배포 과정은 [Hyperledger Fabric 공식 문서 - Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html)를 참조하십시오.
28 | 29 | 1. **테스트 네트워크 실행**
30 | 다음 명령어를 사용하여 두 개의 peer organization과 하나의 order organization으로 구성된 `test-network`를 구축하고 channel을 생성할 수 있습니다. 31 | ```bash 32 | $ cd fabric-sample/test-network 33 | $ ./network.sh up createChannel -c [channel name] -ca -s couchdb 34 | ``` 35 | 2. **체인코드 배포**
36 | `fabric-sample` 디렉터리 하위에 `did-fabric-contract` 프로젝트를 복제합니다. 37 | ```bash 38 | $ cd fabric-sample 39 | $ git clone https://github.com/OmniOneID/did-fabric-contract.git 40 | ``` 41 | `test-network` 디렉터리로 돌아와서 체인코드 배포를 위해 다음 명령어를 실행합니다. 42 | ```bash 43 | $ cd ./test-network 44 | $ ./network.sh deployCC -c [channel name] -ccn [chaincode name] -ccp ../did-fabric-contract/source/did-fabric-contract -ccl go -ccs 1 45 | ``` 46 | 47 |
48 | 49 | ## 실행 예시 50 | OpenDID Chaincode는 `CCKit Framework`를 활용하여 기존 낮은 수준의 체인코드 상태 작업, 복잡한 데이터 처리 작업 등의 문제점을 개선하고 있습니다.
51 | `did-fabric-contract/source/did-fabric-contract/chaincode/opendid.go` 파일의 `NewOpenDIDCC` 함수 내부에서 `CCKit router` 기능을 사용하여 정의되어 있는 다양한 라우팅 경로와 메서드를 확인할 수 있습니다.
52 | (CCKit에 대한 자세한 내용은 [CCKit Github Repository](https://github.com/hyperledger-labs/cckit)를 참조하십시오.) 53 | 54 | ```go 55 | package chaincode 56 | 57 | import ( 58 | "fmt" 59 | 60 | "opendid/chaincode/data" 61 | "opendid/chaincode/service" 62 | 63 | "github.com/hyperledger-labs/cckit/router" 64 | "github.com/hyperledger-labs/cckit/router/param" 65 | ) 66 | 67 | func NewOpenDIDCC() *router.Chaincode { 68 | 69 | r := router.New(`OpenDID`) 70 | 71 | r.Init(Init) 72 | 73 | r.Group(`document_`). 74 | Invoke(`registDidDoc`, registerDidDoc, 75 | param.Struct("InvokedDidDoc", &data.InvokedDidDoc{}), 76 | param.String("roleType")). 77 | Query(`getDidDoc`, getDidDoc, 78 | param.String("da"), 79 | param.String("versionId")). 80 | Invoke(`updateDidDocStatusInService`, updateDidDocStatusInService, 81 | param.String("da"), 82 | param.String("status"), 83 | param.String("versionId")). 84 | Invoke(`updateDidDocStatusRevocation`, updateDidDocStatusRevocation, 85 | param.String("da"), 86 | param.String("status"), 87 | param.String("terminatedTime")) 88 | 89 | r.Group("vcMeta_"). 90 | Invoke("registVcMetadata", registerVcMetadata, 91 | param.Struct("vcMeta", &data.VcMeta{})). 92 | Query("getVcMetadata", getVcMetadata, 93 | param.String("vcId")). 94 | Invoke("updateVcStatus", updateVcStatus, 95 | param.String("vcId"), 96 | param.String("vcStatus")) 97 | 98 | return router.NewChaincode(r) 99 | } 100 | ``` 101 |
102 | 103 | 다음은 `peer` CLI를 사용하여 DID 문서를 블록체인에서 조회하기 위한 `document_getDidDoc` API를 호출하는 예시입니다.
104 | 1. **환경변수 설정**
105 | `peer` CLI 명령어를 사용하기 위해 `test-network` 디렉터리에서 환경변수를 설정합니다. 106 | ```bash 107 | $ export PATH=${PWD}/../bin:$PATH 108 | $ export FABRIC_CFG_PATH=$PWD/../config/ 109 | 110 | $ export CORE_PEER_TLS_ENABLED=true 111 | $ export CORE_PEER_LOCALMSPID=Org1MSP 112 | $ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 113 | $ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 114 | $ export CORE_PEER_ADDRESS=localhost:7051 115 | ``` 116 | 2. **체인코드 호출**
117 | `document_getDidDoc` 함수를 호출하여 DID와 versionId가 각각 `did:open:user` ,`1`에 해당하는 특정 DID 문서를 조회하고 있습니다. 118 | ```bash 119 | $ peer chaincode query -C [channel name] -n [chaincode name] -c '{"Args":["document_getDidDoc","did:open:user","1"]}' 120 | ``` 121 | 3. **결괏값 반환**
122 | 명령이 성공하면 Base64로 인코딩된 `payload`로 결과값이 반환됩니다. 예시 출력은 다음과 같습니다:
123 | ```bash 124 | {"status":200,"payload":"eyJkb2N1...iXX1dfSwic3RhdHVzIjoiQUNUSVZBVEVEIn0"} 125 | ``` 126 | `payload` 값을 디코딩하면, 아래와 같이 조회된 특정 DID 문서를 확인할 수 있습니다. 127 | ```json 128 | { 129 | "document": { 130 | "@context": [ 131 | "https://www.w3.org/ns/did/v1" 132 | ], 133 | "id": "did:opendid:user", 134 | ... 135 | "versionId": "1", 136 | "deactivated": false, 137 | ... 138 | }, 139 | "status": "ACTIVATED" 140 | } 141 | ``` 142 | 위의 예시 출력은 이전에 등록된 DID 문서가 있다고 가정합니다. 등록된 DID 문서가 없는 경우, `null`값이 Base64 인코딩 되어 `payload` 값으로 반환됩니다. 143 | ```bash 144 | {"status":200,"payload":"bnVsbA=="} 145 | ``` 146 | 147 | 148 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported at [technology@omnione.net](mailto:technology@omnione.net). 63 | to the community leaders responsible for enforcement. 64 | 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series 87 | of actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or 94 | permanent ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within 114 | the community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.0, available at 120 | [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. 121 | 122 | Community Impact Guidelines were inspired by 123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available 127 | at [https://www.contributor-covenant.org/translations][translations]. 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | 131 | [v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html 132 | 133 | [Mozilla CoC]: https://github.com/mozilla/diversity 134 | 135 | [FAQ]: https://www.contributor-covenant.org/faq 136 | 137 | [translations]: https://www.contributor-covenant.org/translations -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/opendid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package chaincode 16 | 17 | import ( 18 | "fmt" 19 | 20 | "did-fabric-contract/chaincode/data" 21 | "did-fabric-contract/chaincode/service" 22 | 23 | "github.com/hyperledger-labs/cckit/router" 24 | "github.com/hyperledger-labs/cckit/router/param" 25 | ) 26 | 27 | const ( 28 | CC_VERSION = "did-fabric-contract-1.0.0" 29 | ) 30 | 31 | // NewOpenDIDCC init chaincode function. 32 | func NewOpenDIDCC() *router.Chaincode { 33 | 34 | r := router.New(`OpenDID`) 35 | 36 | r.Init(Init) 37 | 38 | // temp 39 | r.Group(`remove`). 40 | Invoke(``, func(ctx router.Context) (interface{}, error) { 41 | index := string(ctx.GetArgs()[1]) 42 | if err := service.RemoveIndex(ctx, index); err != nil { 43 | return ctx.Response().Error(err), err 44 | } 45 | return ctx.Response().Success(fmt.Sprintf("remove '%s' success", index)), nil 46 | }). 47 | Invoke(`All`, func(ctx router.Context) (interface{}, error) { 48 | if err := service.RemoveAll(ctx); err != nil { 49 | return ctx.Response().Error(err), err 50 | } 51 | return ctx.Response().Success("remove all data success"), nil 52 | }) 53 | 54 | r.Group(`document_`). 55 | Invoke(`registDidDoc`, registerDidDoc, 56 | param.Struct("InvokedDidDoc", &data.InvokedDidDoc{}), 57 | param.String("roleType")). 58 | Query(`getDidDoc`, getDidDoc, 59 | param.String("da"), 60 | param.String("versionId")). 61 | Invoke(`updateDidDocStatusInService`, updateDidDocStatusInService, 62 | param.String("da"), 63 | param.String("status"), 64 | param.String("versionId")). 65 | Invoke(`updateDidDocStatusRevocation`, updateDidDocStatusRevocation, 66 | param.String("da"), 67 | param.String("status"), 68 | param.String("terminatedTime")) 69 | 70 | r.Group("vcMeta_"). 71 | Invoke("registVcMetadata", registerVcMetadata, 72 | param.Struct("vcMeta", &data.VcMeta{})). 73 | Query("getVcMetadata", getVcMetadata, 74 | param.String("vcId")). 75 | Invoke("updateVcStatus", updateVcStatus, 76 | param.String("vcId"), 77 | param.String("vcStatus")) 78 | 79 | return router.NewChaincode(r) 80 | } 81 | 82 | // register a new document router function definition. 83 | func registerDidDoc(ctx router.Context) (interface{}, error) { 84 | invokedDidDoc := ctx.Param("InvokedDidDoc").(data.InvokedDidDoc) 85 | roleType := ctx.ParamString("roleType") 86 | 87 | err := service.RegisterDidDoc(ctx, &invokedDidDoc, data.ROLE_TYPE(roleType)) 88 | if err != nil { 89 | return ctx.Response().Error(err), err 90 | } 91 | return ctx.Response().Success(fmt.Sprintf("document registration successful\n")), nil 92 | } 93 | 94 | // get document in ledger router function definition. 95 | func getDidDoc(ctx router.Context) (interface{}, error) { 96 | da := ctx.ParamString("da") 97 | versionId := ctx.ParamString("versionId") 98 | 99 | result, err := service.GetDidDocAndStatus(ctx, da, versionId) 100 | if err != nil { 101 | return ctx.Response().Error(err), err 102 | } 103 | return ctx.Response().Success(result), nil 104 | } 105 | 106 | // update document in-service status router function definition. 107 | func updateDidDocStatusInService(ctx router.Context) (interface{}, error) { 108 | da := ctx.ParamString("da") 109 | status := ctx.ParamString("status") 110 | versionId := ctx.ParamString("versionId") 111 | 112 | result, err := service.UpdateDidDocStatusInService(ctx, da, versionId, data.DIDDOC_STATUS(status)) 113 | if err != nil { 114 | return ctx.Response().Error(err), err 115 | } 116 | return ctx.Response().Success(result), nil 117 | } 118 | 119 | // update document revocation status router function definition. 120 | func updateDidDocStatusRevocation(ctx router.Context) (interface{}, error) { 121 | da := ctx.ParamString("da") 122 | status := ctx.ParamString("status") 123 | terminatedTime := ctx.ParamString("terminatedTime") 124 | 125 | result, err := service.UpdateDidDocStatusRevocation(ctx, da, data.DIDDOC_STATUS(status), data.UTCDateTime(terminatedTime)) 126 | if err != nil { 127 | return ctx.Response().Error(err), err 128 | } 129 | return ctx.Response().Success(result), nil 130 | } 131 | 132 | // register vcMeta router function definition. 133 | func registerVcMetadata(ctx router.Context) (interface{}, error) { 134 | vcMeta := ctx.Param("vcMeta").(data.VcMeta) 135 | if err := service.RegisterVcMetadata(ctx, vcMeta); err != nil { 136 | return ctx.Response().Error(err), err 137 | } 138 | return ctx.Response().Success(fmt.Sprintf("vc meta registration successful: vcId = %s\n", vcMeta.Id)), nil 139 | } 140 | 141 | // get vcMeta router function definition. 142 | func getVcMetadata(ctx router.Context) (interface{}, error) { 143 | result, err := service.GetVcMetadata(ctx, ctx.ParamString("vcId")) 144 | if err != nil { 145 | return ctx.Response().Error(err), err 146 | } 147 | return ctx.Response().Success(result), nil 148 | } 149 | 150 | // update vcStatus router function definition. 151 | func updateVcStatus(ctx router.Context) (interface{}, error) { 152 | vcId := ctx.ParamString("vcId") 153 | if err := service.UpdateVcStatus(ctx, vcId, data.VC_STATUS(ctx.ParamString("vcStatus"))); err != nil { 154 | return ctx.Response().Error(err), err 155 | } 156 | return ctx.Response().Success(fmt.Sprintf("vc meta update successful: vcId = %s\n", vcId)), nil 157 | } 158 | 159 | func Init(ctx router.Context) (interface{}, error) { 160 | ctx.Logger().Info(fmt.Sprintf("Init open DID CC => version %s", CC_VERSION)) 161 | return fmt.Sprintf("Init open DID CC => version %s", CC_VERSION), nil 162 | } 163 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | We appreciate your contributions! We want to make contributing to this project as easy and transparent as possible, whether it's: 3 | 4 | - Reporting a bug 5 | - Discussing the current state of the code 6 | - Submitting a fix 7 | - Proposing new features 8 | 9 | ## Contribution Process 10 | Thank you for contributing to the project! This guide explains how to contribute to the project, the code style rules, and the review criteria. Please familiarize yourself with the following content before making any contributions. 11 | 12 | 1. **Creating an Issue** 13 | - Before starting any work, create an issue related to the task you wish to work on. All work, including bug fixes, feature improvements, and new proposals, should be initiated after the issue is registered. 14 | - When creating an issue, use the provided issue template and fill in accurate information. 15 | 2. **Issue Assignment** 16 | - Once the issue is created, the administrator will review and may assign the issue to an external contributor. 17 | - Before being assigned, make sure that the same task is not already in progress. 18 | 3. **Fork and Branch Creation** 19 | - Refer to [Pull Request Guidelines](#pull-request-guidelines) 20 | 4. **Writing Code** 21 | - Ensure that the code strictly follows the project's [Coding Style](#coding-style) guidelines. 22 | - Submit the PR after confirming that all tests pass successfully. 23 | 5. **Creating a Pull Request (PR)** 24 | - Commit your work and create a PR. 25 | - In the PR description, provide detailed information about the changes and link the related issue number to connect it to the issue. 26 | - Write concise and clear commit messages. 27 | - Refer to [Commit Message Guideline](#commit-message-guidelines) 28 | 6. **Code Review** 29 | - Once the PR is created, the administrator will review the code. Update the PR by incorporating the reviewer’s feedback. 30 | - Once the review is complete, the administrator will merge the PR. 31 | 32 | ## Detailed Contribution Guide via GitHub 33 | Please refer to [Detailed Contribution Guide via GitHub](https://github.com/OmniOneID/did-doc-architecture/blob/main/how_to_contribute_to_open_did.md) for detailed instructions on how to contribute to the project. This guide includes command examples and screenshots to help you better understand the process. 34 | 35 | ## Code Review Standards 36 | We conduct code reviews based on the following standards to ensure that your contribution maintains consistency with the project and upholds quality: 37 | 38 | 1. **Code Quality** 39 | - Write code that is easy to read and maintain. 40 | - Avoid overly complex logic, and if possible, suggest better solutions. 41 | - Minimize duplicated code and check if the code can be refactored into reusable modules. 42 | 2. **Feature Verification** 43 | - Test the new feature or bug fix to ensure it works as intended. 44 | - All tests must pass before submitting the PR. 45 | - Include any additional necessary tests in the PR. 46 | 3. **Code Style Compliance** 47 | - Ensure that your code follows the project's [Coding Style](#coding-style). 48 | - Feedback will be given if there are formatting issues or violations of naming conventions. 49 | 4. **Commit Messages** 50 | - Ensure that commit messages clearly describe the changes made. 51 | - Avoid including too many modifications in a single commit. If possible, divide changes into smaller commits. 52 | 5. **Documentation** 53 | - If new features, APIs, or configuration changes are introduced, make sure to update or add relevant documentation. 54 | - Write appropriate comments in the code, especially for explaining complex logic. 55 | 56 | ## Code of Conduct 57 | We are committed to fostering a contribution environment where everyone is treated with respect. Please make sure to read and follow the [Code of Conduct](CODE_OF_CONDUCT.md) before starting your contribution. 58 | 59 | ## Issue Reporting Guidelines 60 | We use GitHub Issues to track and manage bugs. 61 | If you encounter a bug, please open a new issue on GitHub. When reporting an issue, please use the provided issue template to clearly describe the problem. This helps us resolve the issue more quickly. 62 | 63 | ### Writing a Good Bug Report 64 | A good bug report includes the following: 65 | - A quick summary or background of the issue. 66 | - Steps to reproduce the bug (be specific and detailed). 67 | - Expected vs. actual results. 68 | - Any additional context or information that could help us diagnose the issue. 69 | 70 | ## Pull Request Guidelines 71 | 1. **Fork** from the `develop` branch of the remote repository. 72 | 2. **Develop the feature**, and ensure the code has been properly tested. 73 | 3. If necessary, update the **documentation** to reflect the changes. 74 | 4. Verify that all tests pass and that the code adheres to our coding style and linting rules. 75 | 5. Once the work is complete, submit a **pull request** to the `develop` branch. 76 | 6. When creating the pull request, assign an appropriate **reviewer** to review the code changes. 77 | It is recommended to choose someone familiar with the codebase, considering their availability for providing feedback. 78 | 7. Also, assign **assignees** to clarify responsibility for the task. 79 | Assign **all maintainers of the repository** as assignees to ensure accountability and a smooth review process. 80 | 81 | > **Note**: Assignees are responsible for ensuring the pull request is reviewed and merged appropriately. Assigning all maintainers as assignees is a crucial step to ensure they are aware of the changes and can respond quickly. 82 | 83 | ## Coding Style 84 | Our coding style is based on the [OpenDID Coding Style](https://github.com/OmniOneID/did-doc-architecture/blob/main/docs/rules/coding_style.md). Adhering to these guidelines ensures that the code is clean, readable, and maintainable. 85 | 86 | ## Document Creation and Editing Guide 87 | Our document creation process follows the [OpenDID Document Guide](https://github.com/OmniOneID/did-doc-architecture/blob/main/docs/guide/docs/write_document_guide.md). Most of the design documents we create use the Markdown (*.md) format, ensuring consistency and ease of collaboration. 88 | 89 | ## Commit Message Guidelines 90 | Our commit messages follow the [OpenDID Commit Rule](https://github.com/OmniOneID/did-doc-architecture/blob/main/docs/rules/git_code_commit_rule.md). Well-structured commit messages help others understand the intent behind your changes and make it easier to navigate the code history. 91 | 92 | ## Signing the CLA 93 | Before we can accept your pull request, you must submit a CLA. This only needs to be done once. Complete your CLA here: [Contributor License Agreement](CLA.md) 94 | 95 | ## License 96 | [Apache 2.0](LICENSE) -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/utility/crypto.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package utility 16 | 17 | import ( 18 | "crypto/ecdsa" 19 | "crypto/elliptic" 20 | "crypto/rand" 21 | "crypto/sha256" 22 | "did-fabric-contract/chaincode/data" 23 | "encoding/base32" 24 | "encoding/base64" 25 | "encoding/hex" 26 | "fmt" 27 | "math/big" 28 | 29 | "github.com/btcsuite/btcutil/base58" 30 | ) 31 | 32 | func CreateNewEcdsaPrivateKey() (*ecdsa.PrivateKey, error) { 33 | return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 34 | } 35 | 36 | func Sign(data []byte, privateKey *ecdsa.PrivateKey) ([]byte, error) { 37 | digest := sha256.Sum256(data) 38 | 39 | r, s, err := ecdsa.Sign(rand.Reader, privateKey, digest[:]) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | params := privateKey.Curve.Params() 45 | curveOrderByteSize := params.P.BitLen() / 8 46 | 47 | rBytes := r.Bytes() 48 | sBytes := s.Bytes() 49 | 50 | signature := make([]byte, curveOrderByteSize*2) 51 | copy(signature[curveOrderByteSize-len(rBytes):], rBytes) 52 | copy(signature[curveOrderByteSize*2-len(sBytes):], sBytes) 53 | 54 | return signature, nil 55 | } 56 | 57 | func Verify(data, signature []byte, publicKey *ecdsa.PublicKey) bool { 58 | digest := sha256.Sum256(data) 59 | 60 | curveOrderByteSize := publicKey.Curve.Params().P.BitLen() / 8 61 | 62 | r, s := new(big.Int), new(big.Int) 63 | r.SetBytes(signature[:curveOrderByteSize]) 64 | s.SetBytes(signature[curveOrderByteSize:]) 65 | 66 | return ecdsa.Verify(publicKey, digest[:], r, s) 67 | } 68 | 69 | func DecompressPublicKeyFromString(publicKeyHexString string) (*ecdsa.PublicKey, error) { 70 | publicKeyBytes, err := hex.DecodeString(publicKeyHexString) 71 | if err != nil { 72 | return nil, err 73 | } 74 | 75 | return DecompressPublicKey(publicKeyBytes) 76 | } 77 | 78 | func DecompressPublicKey(publicKey []byte) (*ecdsa.PublicKey, error) { 79 | if len(publicKey) != 33 { 80 | return nil, fmt.Errorf("invalid public key size: %d, expected 33", len(publicKey)) 81 | } 82 | 83 | if publicKey[0] != 0x02 && publicKey[0] != 0x03 { 84 | return nil, fmt.Errorf("invalid public key format: first byte must be 0x02 or 0x03") 85 | } 86 | 87 | x := new(big.Int).SetBytes(publicKey[1:]) 88 | xx := new(big.Int).Mul(x, x) 89 | xxx := new(big.Int).Mul(xx, x) 90 | 91 | ax := new(big.Int).Mul(big.NewInt(3), x) 92 | 93 | yy := new(big.Int).Sub(xxx, ax) 94 | yy.Add(yy, elliptic.P256().Params().B) 95 | 96 | y1 := new(big.Int).ModSqrt(yy, elliptic.P256().Params().P) 97 | if y1 == nil { 98 | return nil, fmt.Errorf("can not recovery public key") 99 | } 100 | 101 | y2 := new(big.Int).Neg(y1) 102 | y2.Mod(y2, elliptic.P256().Params().P) 103 | 104 | y := new(big.Int) 105 | if publicKey[0] == 0x02 { 106 | if y1.Bit(0) == 0 { 107 | y = y1 108 | } else { 109 | y = y2 110 | } 111 | } else { 112 | if y1.Bit(0) == 1 { 113 | y = y1 114 | } else { 115 | y = y2 116 | } 117 | } 118 | 119 | return &ecdsa.PublicKey{X: x, Y: y, Curve: elliptic.P256()}, nil 120 | } 121 | 122 | func CompressPublicKey(publicKey *ecdsa.PublicKey) []byte { 123 | params := publicKey.Curve.Params() 124 | curveOrderByteSize := params.P.BitLen() / 8 125 | 126 | xBytes := publicKey.X.Bytes() 127 | signature := make([]byte, curveOrderByteSize+1) 128 | 129 | if publicKey.Y.Bit(0) == 1 { 130 | signature[0] = 0x03 131 | } else { 132 | signature[0] = 0x02 133 | } 134 | 135 | copy(signature[1+curveOrderByteSize-len(xBytes):], xBytes) 136 | return signature 137 | } 138 | 139 | func RecoveryEcdsa(data []byte, rawSign []byte) (*ecdsa.PublicKey, *ecdsa.PublicKey, error) { 140 | signLength := len(rawSign) 141 | halfSignLength := signLength / 2 142 | 143 | r := new(big.Int).SetBytes(rawSign[:halfSignLength]) 144 | s := new(big.Int).SetBytes(rawSign[halfSignLength:]) 145 | curve := elliptic.P256().Params() 146 | 147 | expY := new(big.Int).Sub(curve.N, big.NewInt(2)) 148 | rInv := new(big.Int).Exp(r, expY, curve.N) 149 | z := new(big.Int).SetBytes(data) 150 | 151 | xx := new(big.Int).Mul(r, r) 152 | xxx := xx.Mul(xx, r) 153 | 154 | ax := new(big.Int).Mul(big.NewInt(3), r) 155 | 156 | yy := new(big.Int).Sub(xxx, ax) 157 | yy.Add(yy, elliptic.P256().Params().B) 158 | 159 | y1 := new(big.Int).ModSqrt(yy, curve.P) 160 | if y1 == nil { 161 | return nil, nil, fmt.Errorf("cannot recover public key") 162 | } 163 | 164 | y2 := new(big.Int).Neg(y1) 165 | y2.Mod(y2, curve.P) 166 | 167 | rInvBytes := rInv.Bytes() 168 | 169 | p1, p2 := elliptic.P256().ScalarMult(r, y1, s.Bytes()) 170 | p3, p4 := elliptic.P256().ScalarBaseMult(z.Bytes()) 171 | 172 | p5 := new(big.Int).Neg(p4) 173 | p5.Mod(p5, curve.P) 174 | 175 | q1, q2 := elliptic.P256().Add(p1, p2, p3, p5) 176 | q3, q4 := elliptic.P256().ScalarMult(q1, q2, rInvBytes) 177 | 178 | n1, n2 := elliptic.P256().ScalarMult(r, y2, s.Bytes()) 179 | n3, n4 := elliptic.P256().ScalarBaseMult(z.Bytes()) 180 | 181 | n5 := new(big.Int).Neg(n4) 182 | n5.Mod(n5, curve.P) 183 | 184 | q5, q6 := elliptic.P256().Add(n1, n2, n3, n5) 185 | q7, q8 := elliptic.P256().ScalarMult(q5, q6, rInvBytes) 186 | 187 | key1 := ecdsa.PublicKey{Curve: elliptic.P256(), X: q3, Y: q4} 188 | key2 := ecdsa.PublicKey{Curve: elliptic.P256(), X: q7, Y: q8} 189 | 190 | return &key1, &key2, nil 191 | } 192 | 193 | func ComparePublicKey(key1, key2 *ecdsa.PublicKey) bool { 194 | x := key1.X.Cmp(key2.X) 195 | y := key1.Y.Cmp(key2.Y) 196 | 197 | if x == 0 && y == 0 { 198 | return true 199 | } 200 | 201 | return false 202 | } 203 | 204 | func DecodeMultibase(input data.Multibase) ([]byte, error) { 205 | multibaseData := string(input) 206 | if len(multibaseData) < 1 { 207 | return nil, fmt.Errorf("input data is too short") 208 | } 209 | 210 | encodingType := multibaseData[0] 211 | encodingData := multibaseData[1:] 212 | 213 | switch encodingType { 214 | case 'f', 'F': 215 | return hex.DecodeString(encodingData) 216 | case 'z': 217 | return base58.Decode(encodingData), nil 218 | case 'b': 219 | return base32.StdEncoding.DecodeString(encodingData) 220 | case 'm': 221 | return base64.RawStdEncoding.DecodeString(encodingData) 222 | case 'u': 223 | return base64.URLEncoding.DecodeString(encodingData) 224 | default: 225 | return nil, fmt.Errorf("unsupported encoding : %c", encodingType) 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /source/did-fabric-contract/README.md: -------------------------------------------------------------------------------- 1 | # Fabric Contract Guide 2 | This document is a guide for using the OpenDID Chaincode. The Chaincode provides functionality to store and manage the necessary DID Document and Verifiable Credential Metadata(hereafter VC Meta) information for OpenDID on the blockchain. The Chaincode processes requests received from the Blockchain SDK to generate and record transactions. 3 | 4 | ## S/W Specifications 5 | | Category | Details | 6 | |----------|------------------------| 7 | | Language | Golang 1.22 | 8 | 9 |
10 | 11 | ## Chaincode Features 12 | The OpenDID Chaincode provides transaction processing functions related to DID documents and VC metadata. The functions called via the routing function NewOpenDIDCC are as follows: 13 | 14 | * document_registerDidDoc: Registers/updates a new DID document and saves its state. 15 | * document_getDidDoc: Retrieves a specific DID document and its state. 16 | * document_updateDidDocStatusInService: Changes the status of a DID document to "In-Service". 17 | * document_updateDidDocStatusRevocation: Changes the status of a DID document to "Revocation". 18 | * vcMeta_registerVcMetadata: Registers VC metadata. 19 | * vcMeta_getVcMetadata: Retrieves specific VC metadata. 20 | * vcMeta_updateVcStatus: Changes the status of VC metadata. 21 | 22 |
23 | 24 | ## Installation and Deployment 25 | You can easily set up a Fabric network using the test network provided by Hyperledger Fabric.
26 | Refer to the [Hyperledger Fabric official documentation - Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html) for more details on the network setup and chaincode deployment process outlined below. 27 | 1. **Start the Test Network**
28 | Use the following command to set up the `test-network` composed of two peer organizations and one orderer organization, and create a channel. 29 | ```bash 30 | $ cd fabric-sample/test-network 31 | $ ./network.sh up createChannel -c [channel name] -ca -s couchdb 32 | ``` 33 | 2. **Deploy Chaincode**
34 | Clone the `did-fabric-contract` project under the `fabric-sample` directory. 35 | ```bash 36 | $ cd fabric-sample 37 | $ git clone https://github.com/OmniOneID/did-fabric-contract.git 38 | ``` 39 | Go back to the `test-network` directory and execute the following command to deploy the chaincode. 40 | ```bash 41 | $ cd ./test-network 42 | $ ./network.sh deployCC -c [channel name] -ccn [chaincode name] -ccp ../did-fabric-contract/source/did-fabric-contract -ccl go -ccs 1 43 | ``` 44 | 45 |
46 | 47 | ## Example Execution 48 | The OpenDID Chaincode improves issues such as low-level chaincode state operations and complex data processing tasks by utilizing the `CCKit Framework`. 49 | In the `NewOpenDIDCC` function inside the `did-fabric-contract/source/did-fabric-contract/chaincode/opendid.go` file, you can see the various routing paths and methods defined using the `CCKit router` functionality. 50 | (For more details on CCKit, refer to the [CCKit Github Repository](https://github.com/hyperledger-labs/cckit).) 51 | 52 | ```go 53 | package chaincode 54 | 55 | import ( 56 | "fmt" 57 | 58 | "opendid/chaincode/data" 59 | "opendid/chaincode/service" 60 | 61 | "github.com/hyperledger-labs/cckit/router" 62 | "github.com/hyperledger-labs/cckit/router/param" 63 | ) 64 | 65 | func NewOpenDIDCC() *router.Chaincode { 66 | 67 | r := router.New(`OpenDID`) 68 | 69 | r.Init(Init) 70 | 71 | r.Group(`document_`). 72 | Invoke(`registDidDoc`, registerDidDoc, 73 | param.Struct("InvokedDidDoc", &data.InvokedDidDoc{}), 74 | param.String("roleType")). 75 | Query(`getDidDoc`, getDidDoc, 76 | param.String("da"), 77 | param.String("versionId")). 78 | Invoke(`updateDidDocStatusInService`, updateDidDocStatusInService, 79 | param.String("da"), 80 | param.String("status"), 81 | param.String("versionId")). 82 | Invoke(`updateDidDocStatusRevocation`, updateDidDocStatusRevocation, 83 | param.String("da"), 84 | param.String("status"), 85 | param.String("terminatedTime")) 86 | 87 | r.Group("vcMeta_"). 88 | Invoke("registVcMetadata", registerVcMetadata, 89 | param.Struct("vcMeta", &data.VcMeta{})). 90 | Query("getVcMetadata", getVcMetadata, 91 | param.String("vcId")). 92 | Invoke("updateVcStatus", updateVcStatus, 93 | param.String("vcId"), 94 | param.String("vcStatus")) 95 | 96 | return router.NewChaincode(r) 97 | } 98 | ``` 99 |
100 | 101 | Below is an example of calling the `document_getDidDoc` API to retrieve a DID document from the blockchain using the `peer` CLI. 102 | 1. **Set Environment Variables** 103 | Set the environment variables in the `test-network` directory to use the `peer` CLI commands. 104 | ```bash 105 | $ export PATH=${PWD}/../bin:$PATH 106 | $ export FABRIC_CFG_PATH=$PWD/../config/ 107 | 108 | $ export CORE_PEER_TLS_ENABLED=true 109 | $ export CORE_PEER_LOCALMSPID=Org1MSP 110 | $ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 111 | $ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 112 | $ export CORE_PEER_ADDRESS=localhost:7051 113 | ``` 114 | 2. **Invoke Chaincode** 115 | The `document_getDidDoc` function is called to retrieve a specific DID document where the DID is `did:open:user` and the versionId is `1`. 116 | ```bash 117 | $ peer chaincode query -C [channel name] -n [chaincode name] -c '{"Args":["document_getDidDoc","did:open:user","1"]}' 118 | ``` 119 | 3. **Return Result** 120 | If the command is successful, the result is returned as a `payload` encoded in Base64. The example output is as follows: 121 | ```bash 122 | {"status":200,"payload":"eyJkb2N1...iXX1dfSwic3RhdHVzIjoiQUNUSVZBVEVEIn0"} 123 | ``` 124 | Decoding the `payload` value will reveal the retrieved specific DID document as shown below: 125 | ```json 126 | { 127 | "document": { 128 | "@context": [ 129 | "https://www.w3.org/ns/did/v1" 130 | ], 131 | "id": "did:opendid:user", 132 | ... 133 | "versionId": "1", 134 | "deactivated": false, 135 | ... 136 | }, 137 | "status": "ACTIVATED" 138 | } 139 | ``` 140 | The above example output assumes that there is a previously registered DID document. If no DID document is registered, a `null` value is encoded in Base64 and returned as the `payload`. 141 | ```bash 142 | {"status":200,"payload":"bnVsbA=="} 143 | ``` 144 | -------------------------------------------------------------------------------- /docs/api/ContractError.md: -------------------------------------------------------------------------------- 1 | --- 2 | puppeteer: 3 | pdf: 4 | format: A4 5 | displayHeaderFooter: true 6 | landscape: false 7 | scale: 0.8 8 | margin: 9 | top: 1.2cm 10 | right: 1cm 11 | bottom: 1cm 12 | left: 1cm 13 | image: 14 | quality: 100 15 | fullPage: false 16 | --- 17 | 18 | ContractError 19 | == 20 | 21 | - Topic: ContractError 22 | - Author: Kim Jeong-heon, Kim Min-yong 23 | - Date: 2024-08-29 24 | - Version: v1.0.0 25 | 26 | | Version | Date | Changes | 27 | | ---------------- | ---------- | ------------------------ | 28 | | v1.0.0 | 2024-08-29 | Initial version | 29 | 30 |
31 | 32 | # Table of Contents 33 | - [ContractError](#contracterror) 34 | - [Table of Contents](#table-of-contents) 35 | - [Model](#model) 36 | - [ContractError](#contracterror-1) 37 | - [Description](#description) 38 | - [Declaration](#declaration) 39 | - [Property](#property) 40 | - [Error Code](#error-code) 41 | - [1. DID Document(01XXX)](#1-did-document01xxx) 42 | - [2. DID Document Status(02XXX)](#2-did-document-status02xxx) 43 | - [3. Verifiable Credential Metadata(03XXX)](#3-verifiable-credential-metadata03xxx) 44 | 45 | # Model 46 | ## ContractError 47 | 48 | ### Description 49 | ``` 50 | Error struct for Fabric Contract. It has code and message pair. 51 | Code starts with SSRVFCC. 52 | ``` 53 | 54 | ### Declaration 55 | ```go 56 | // Declaration in Golang 57 | type ContractError struct { 58 | Code string 59 | Message string 60 | } 61 | ``` 62 | 63 | ### Property 64 | 65 | | Name | Type | Description | **M/O** | **Note** | 66 | |----------------|------------|----------------------------------------|---------|------------------| 67 | | code | String | Error code. It starts with SSRVFCC | M | | 68 | | message | String | Error description | M | | 69 | 70 |
71 | 72 | # Error Code 73 | ## 1. DID Document(01XXX) 74 | 75 | | Error Code | Error Message | Description | Action Required | 76 | |--------------|-----------------------------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------| 77 | | SSRVFCC01001 | Failed to insert did document | Cannot insert a DID document into the blockchain state. | Verify DID document data validity and ensure there are no key id conflicts. Depend on detail error cases | 78 | | SSRVFCC01002 | Failed to get did document | Cannot retrieve the DID document from the ledger. | Ensure that the DID document status exists in the ledger | 79 | | SSRVFCC01003 | Failed to update did document | Cannot update the DID document in the blockchain state. | Verify DID document data validity | 80 | | SSRVFCC01004 | Provider is invalid | The specified provider is not recognized or invalid. | Check the provider's key id and role type | 81 | | SSRVFCC01005 | Failed to convert json data to did document | JSON data could not be converted to a DID document struct | Validate the DID document json format | 82 | | SSRVFCC01006 | Failed to signature verification | Signature verification for the DID document failed. | Verify the signature value and plain text. Depend on detail error cases | 83 | | SSRVFCC01007 | VerificationMethod is invalid | The verification method used is invalid or unsupported. | Check the verification method is used. | 84 | | SSRVFCC01008 | VersionId is invalid | The provided VersionId is not valid | Check versionId of current and previous did documents | 85 | 86 | 87 |
88 | 89 | ## 2. DID Document Status(02XXX) 90 | 91 | | Error Code | Error Message | Description | Action Required | 92 | |--------------|----------------------------------------------------|-----------------------------------------------------------------------------|------------------------------------------------------| 93 | | SSRVFCC02001 | Failed to insert did document status | Cannot insert the DID document status into the blockchain state. | Verify DID document data validity and ensure there are no key id conflicts. Depend on detail error cases | 94 | | SSRVFCC02002 | Failed to get did document status | Cannot retrieve the DID document status from the ledger. | Ensure that the DID document status exists in the ledger | 95 | | SSRVFCC02003 | Failed to update did document status | Cannot update the DID document status in the blockchain state. | Verify the correctness of the status | 96 | | SSRVFCC02004 | Failed to convert json data to did document status | JSON data could not be converted to the DID document status struct. | Validate the DID document status JSON format | 97 | | SSRVFCC02005 | Did document status is invalid | The provided DID document status is invalid or not recognized. | Verify the DID document status | 98 | 99 | 100 |
101 | 102 | ## 3. Verifiable Credential Metadata(03XXX) 103 | 104 | | Error Code | Error Message | Description | Action Required | 105 | |--------------|----------------------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------| 106 | | SSRVFCC03001 | Failed to insert vc meta | Cannot insert VC meta into the blockchain state. | Verify VC meta data validity and ensure there are no key id conflicts. Depend on detail error cases | 107 | | SSRVFCC03002 | Failed to get vc meta | Cannot retrieve the VC meta from the ledger. | Ensure that the VC meta exists in the ledger | 108 | | SSRVFCC03003 | Failed to update vc meta | Cannot update the VC meta in the blockchain state. | Verify the correctness of the vc meta status | 109 | | SSRVFCC03004 | Failed to convert json data to vc meta | JSON data could not be converted to the VC meta struct. | Validate the VC meta JSON format | 110 | | SSRVFCC03005 | VC meta status is invalid | The provided VC meta status is not valid or recognized. | Verify the VC meta status | -------------------------------------------------------------------------------- /CLA.md: -------------------------------------------------------------------------------- 1 | # Individual Software Grant and Contributor License Agreement 2 | ## Based on the Apache Software Foundation Software Grant and Individual Contributor License Agreement 3 | ### http://www.apache.org/licenses/ 4 | 5 | Thank you for your interest in the OpenDID project (the “Project”). In order to clarify the 6 | intellectual property license granted with Contributions (defined below) from any person or 7 | entity, the Project must have a Contributor License Agreement (“CLA”) on file that has been 8 | signed by each Contributor, indicating agreement to the license terms below. This license is for 9 | your protection as a Contributor as well as the protection of the Project and its users; it does 10 | not change your rights to use your own Contributions for any other purpose. 11 | 12 | You accept and agree to the following terms and conditions for Your present and future 13 | Contributions submitted to the Project. In return, the Project shall not use Your Contributions in 14 | a way that is contrary to the public benefit or inconsistent with its nonprofit status and bylaws 15 | in effect at the time of the Contribution. Except for the license granted herein to the Project 16 | and recipients of software distributed by the Project, You reserve all right, title, and interest in 17 | and to Your Contributions. 18 | 19 | **1. Definitions.** 20 | This document is a CLA (Contributor License Agreement) that must be signed by all Contributors to the Project. 21 | **“You”** or **“Your”** shall mean the copyright owner or legal entity authorized by the copyright owner that is making this CLA with the Project. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, “control” means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 22 | **“Contribution”** shall mean the code, documentation or other original works of authorship expressly identified in Schedule A, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to the Project for inclusion in, or documentation of, any of the products owned or managed by the Project (the **“Work”**). For the purposes of this definition, “submitted” means any form of electronic, verbal, or written communication sent to the Project or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as “Not a Contribution.” 23 | 24 | **2. Grant of Copyright License.** 25 | Subject to the terms and conditions of this CLA, You hereby grant to the Project and to recipients of software distributed by the Project a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. 26 | For the avoidance of doubt, by agreeing to this CLA, You confirm that the Project and recipients of software distributed by the Project are free to use the code, documentation, or other original works of authorship that You submit as part of Your Contributions. 27 | 28 | **3. Grant of Patent License.** 29 | Subject to the terms and conditions of this CLA, You hereby grant to the Project and to recipients of software distributed by the Project a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. 30 | Should any entity initiate patent litigation against you or any other entity (imcluding through a cross-claim or counterclaim in a lawsuit), alleging that your Contribution or the Work to which you have contributed constitutes direct or contributory patent infrigement, any patent licenses granted to that entity for the Contribution or Work shall be terminated as of the date such litigation is filed. 31 | 32 | **4. Representations with Respect to the License and Contributions.** 33 | You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to the Project, or that your employer has executed a separate Corporate CLA with the Project. 34 | 35 | **5. Additional Representations with Respect to Contributions.** 36 | You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions. 37 | 38 | **6. Disclaimers.** 39 | You have no additional obligations, such as making further code support, after making a Contribution, and any support for Your Contribution is at Your discretion. 40 | You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASE, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. 41 | Also, You shall retain the rights to Your Contribution and may use it for other projects or purposes. 42 | 43 | **7. Non-Original Creations.** 44 | Should You wish to submit work that is not Your original creation, You may submit it to the Project separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as “Submitted on behalf of a third-party: [named here].” 45 | Additionally, if submitting non-original works, You must cleary specify the original author's license and submit it as a separate file. 46 | If You violate this obligation by submitting a third party's work without proper authorization, resulting in copyright infrigement, You shall be solely responsible for any legal liabilities arising from such infrigement. 47 | 48 | **8. Agreements.** 49 | You agree to notify the Project of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect. 50 | "To sign this CLA, please follow the automated procedure on GitHub or download the PDF, sign it, and submit it to technology@omnione.net." 51 | -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/repository/document_repository.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package repository 16 | 17 | import ( 18 | "did-fabric-contract/chaincode/data" 19 | . "did-fabric-contract/chaincode/error" 20 | "encoding/json" 21 | 22 | "github.com/hyperledger-labs/cckit/router" 23 | ) 24 | 25 | // InsertDidDocLatest 26 | /* 27 | The function inserts the provided DID document into the ledger. 28 | 29 | * @param ctx The router context used for state management. 30 | * @param didDoc The DID document to be inserted into the ledger. 31 | 32 | * @return An error if any issue occurred during the insertion, otherwise nil. 33 | */ 34 | func InsertDidDocLatest(ctx router.Context, didDoc *data.DidDoc) error { 35 | if err := ctx.State().Insert(didDoc); err != nil { 36 | return GetContractError(DIDDOC_INSERT_ERROR, err) 37 | } 38 | return nil 39 | } 40 | 41 | // GetDidDocLatest 42 | /* 43 | The function retrieves the latest DID document from the ledger. 44 | 45 | * @param ctx The router context used for state management. 46 | * @param did The DID of the DID document to retrieve. 47 | 48 | * @return The DID document containing the latest data if successful. 49 | * @return An error if any issue occurred during retrieval or conversion. 50 | */ 51 | func GetDidDocLatest(ctx router.Context, did string) (*data.DidDoc, error) { 52 | result, err := ctx.State().Get(&data.DidDoc{Id: did}) 53 | var didDoc *data.DidDoc 54 | if err != nil { 55 | return nil, GetContractError(DIDDOC_GET_ERROR, err) 56 | } 57 | if err := json.Unmarshal(result.([]uint8), &didDoc); err != nil { 58 | return nil, GetContractError(DIDDOC_CONVERT_ERROR, err) 59 | } 60 | return didDoc, nil 61 | } 62 | 63 | // PutDidDocLatest 64 | /* 65 | The function updates the provided DID document in the ledger. 66 | 67 | * @param ctx The router context used for state management. 68 | * @param didDoc The DID document to be updated in the ledger. 69 | 70 | * @return An error if any issue occurred during the update, otherwise nil. 71 | */ 72 | func PutDidDocLatest(ctx router.Context, didDoc *data.DidDoc) error { 73 | if err := ctx.State().Put(didDoc); err != nil { 74 | return GetContractError(DIDDOC_PUT_ERROR, err) 75 | } 76 | return nil 77 | } 78 | 79 | // IsExistDidDocLatest 80 | /* 81 | The function checks if a DID document with the specified DID exists in the ledger. 82 | 83 | * @param ctx The router context used for state management. 84 | * @param da The DID of the DID document to check for existence. 85 | 86 | * @return True if the DID document exists, otherwise false. 87 | * @return An error if any issue occurred during the check. 88 | */ 89 | func IsExistDidDocLatest(ctx router.Context, da string) (bool, error) { 90 | return ctx.State().Exists(&data.DidDoc{Id: da}) 91 | } 92 | 93 | // InsertDidDocWithVersionId 94 | /* 95 | The function inserts the provided DID document with version ID into the ledger. 96 | 97 | * @param ctx The router context used for state management. 98 | * @param didDoc The DID document with version ID to be inserted into the ledger. 99 | 100 | * @return An error if any issue occurred during the insertion, otherwise nil. 101 | */ 102 | func InsertDidDocWithVersionId(ctx router.Context, didDoc *data.DidDocWithVersionId) error { 103 | if err := ctx.State().Insert(didDoc); err != nil { 104 | return GetContractError(DIDDOC_INSERT_ERROR, err) 105 | } 106 | return nil 107 | } 108 | 109 | // GetDidDocWithVersionID 110 | /* 111 | The function retrieves the DID document with the specified version ID from the ledger. 112 | 113 | * @param ctx The router context used for state management. 114 | * @param did The DID of the DID document to retrieve. 115 | * @param versionId The version ID of the DID document to retrieve. 116 | 117 | * @return The DID document with the specified version ID if found. 118 | * @return An error if any issue occurred during retrieval or conversion. 119 | */ 120 | func GetDidDocWithVersionID(ctx router.Context, did string, versionId string) (*data.DidDoc, error) { 121 | result, err := ctx.State().Get(&data.DidDocWithVersionId{DidDoc: data.DidDoc{Id: did, VersionId: versionId}}) 122 | var didDocWithVersionId *data.DidDocWithVersionId 123 | if err != nil { 124 | return nil, GetContractError(DIDDOC_GET_ERROR, err) 125 | } 126 | if err := json.Unmarshal(result.([]uint8), &didDocWithVersionId); err != nil { 127 | return nil, GetContractError(DIDDOC_CONVERT_ERROR, err) 128 | } 129 | return &didDocWithVersionId.DidDoc, nil 130 | } 131 | 132 | // PutDidDocWithVersionId 133 | /* 134 | The function updates the provided DID document with version ID in the ledger. 135 | 136 | * @param ctx The router context used for state management. 137 | * @param didDocWithVersionId The DID document with version ID to be updated in the ledger. 138 | 139 | * @return An error if any issue occurred during the update, otherwise nil. 140 | */ 141 | func PutDidDocWithVersionId(ctx router.Context, didDocWithVersionId *data.DidDocWithVersionId) error { 142 | if err := ctx.State().Put(didDocWithVersionId); err != nil { 143 | return GetContractError(DIDDOC_PUT_ERROR, err) 144 | } 145 | return nil 146 | } 147 | 148 | // InsertDocumentStatus 149 | /* 150 | The function inserts the provided document status into the ledger. 151 | 152 | * @param ctx The router context used for state management. 153 | * @param documentStatus The document status to be inserted into the ledger. 154 | 155 | * @return An error if any issue occurred during the insertion, otherwise nil. 156 | */ 157 | func InsertDocumentStatus(ctx router.Context, documentStatus *data.DocumentStatus) error { 158 | if err := ctx.State().Insert(documentStatus); err != nil { 159 | return GetContractError(DIDDOC_STATUS_INSERT_ERROR, err) 160 | } 161 | return nil 162 | } 163 | 164 | // PutDocumentStatus 165 | /* 166 | The function updates the provided document status in the ledger. 167 | 168 | * @param ctx The router context used for state management. 169 | * @param documentStatus The document status to be updated in the ledger. 170 | 171 | * @return An error if any issue occurred during the update, otherwise nil. 172 | */ 173 | func PutDocumentStatus(ctx router.Context, documentStatus *data.DocumentStatus) error { 174 | if err := ctx.State().Put(documentStatus); err != nil { 175 | return GetContractError(DIDDOC_STATUS_PUT_ERROR, err) 176 | } 177 | return nil 178 | } 179 | 180 | // GetDocumentStatus 181 | /* 182 | The function retrieves the document status for the specified DID from the ledger. 183 | 184 | * @param ctx The router context used for state management. 185 | * @param did The DID of the document status to retrieve. 186 | 187 | * @return The document status associated with the specified DID if found. 188 | * @return An error if any issue occurred during retrieval or conversion. 189 | */ 190 | func GetDocumentStatus(ctx router.Context, did string) (*data.DocumentStatus, error) { 191 | result, err := ctx.State().Get(&data.DocumentStatus{Id: did}) 192 | var documentStatus *data.DocumentStatus 193 | if err != nil { 194 | return nil, GetContractError(DIDDOC_STATUS_GET_ERROR, err) 195 | } 196 | if err := json.Unmarshal(result.([]uint8), &documentStatus); err != nil { 197 | return nil, GetContractError(DIDDOC_STATUS_CONVERT_ERROR, err) 198 | } 199 | return documentStatus, json.Unmarshal(result.([]uint8), &documentStatus) 200 | } 201 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2024 OmniOne. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /source/did-fabric-contract/chaincode/service/document_service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 OmniOne. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package service 16 | 17 | import ( 18 | "did-fabric-contract/chaincode/data" 19 | . "did-fabric-contract/chaincode/error" 20 | "did-fabric-contract/chaincode/repository" 21 | "did-fabric-contract/chaincode/utility" 22 | "encoding/json" 23 | "fmt" 24 | "log" 25 | "strings" 26 | 27 | "github.com/hyperledger-labs/cckit/state" 28 | 29 | "github.com/hyperledger-labs/cckit/router" 30 | "gopkg.in/go-playground/validator.v9" 31 | ) 32 | 33 | // RemoveIndex 34 | /* 35 | The function removes the state associated with the given index from the ledger. 36 | 37 | * @param ctx The router context used for state management. 38 | * @param index The index of the state to be removed. 39 | 40 | * @return An error if the removal fails, otherwise nil. 41 | */ 42 | func RemoveIndex(ctx router.Context, index string) error { 43 | return ctx.Stub().DelState(index) 44 | } 45 | 46 | // RemoveAll 47 | /* 48 | The function removes all states from the ledger that match predefined prefixes. 49 | 50 | * @param ctx The router context used for state management. 51 | 52 | * @return An error if the removal fails, otherwise nil. Returns an error if no data is found. 53 | */ 54 | func RemoveAll(ctx router.Context) error { 55 | jsonQuery := make(map[string]interface{}) 56 | 57 | selector := make(map[string]interface{}) 58 | jsonQuery["selector"] = selector 59 | 60 | id := make(map[string]interface{}) 61 | selector["_id"] = id 62 | 63 | orConditions := []interface{}{ 64 | map[string]interface{}{"$regex": data.DIDDOC_PREFIX}, 65 | map[string]interface{}{"$regex": data.DIDDOC_STATUS_PREFIX}, 66 | map[string]interface{}{"$regex": data.VCMETA_PREFIX}, 67 | } 68 | id["$or"] = orConditions 69 | 70 | query, _ := json.Marshal(jsonQuery) 71 | iterator, err := ctx.Stub().GetQueryResult(string(query)) 72 | if err != nil { 73 | return err 74 | } 75 | defer iterator.Close() 76 | 77 | if !iterator.HasNext() { 78 | return fmt.Errorf("cannot found data") 79 | } 80 | 81 | for iterator.HasNext() { 82 | queryResponse, _ := iterator.Next() 83 | ctx.Stub().DelState(queryResponse.Key) 84 | } 85 | 86 | return nil 87 | } 88 | 89 | // RegisterDidDoc 90 | /* 91 | The function registers a DID document into the ledger after validating and converting it. 92 | 93 | * @param ctx The router context used for state management. 94 | * @param invokedDidDoc The invoked DID document to be registered. 95 | * @param roleType The role type of the DID document. 96 | 97 | * @return An error if the registration fails, otherwise nil. 98 | */ 99 | func RegisterDidDoc(ctx router.Context, invokedDidDoc *data.InvokedDidDoc, roleType data.ROLE_TYPE) error { 100 | 101 | if err := validateInvokedDidDoc(ctx, invokedDidDoc, roleType); err != nil { 102 | return err 103 | } 104 | didDoc, err := convertFromMultiBaseToDocument(invokedDidDoc.DidDoc) 105 | if err != nil { 106 | return GetContractError(DIDDOC_CONVERT_ERROR, err) 107 | } 108 | documentStatus := data.MakeDocumentStatus(didDoc, roleType) 109 | return saveOrUpdateDocument(ctx, didDoc, documentStatus) 110 | } 111 | 112 | // validateInvokedDidDoc 113 | /* 114 | The function validates the invoked DID document based on the role type and signature. 115 | 116 | * @param ctx The router context used for state management. 117 | * @param invokedDidDoc The invoked DID document to be validated. 118 | * @param roleType The role type of the DID document. 119 | 120 | * @return An error if the validation fails, otherwise nil. 121 | */ 122 | func validateInvokedDidDoc(ctx router.Context, invokedDidDoc *data.InvokedDidDoc, roleType data.ROLE_TYPE) error { 123 | if roleType == data.TAS { 124 | return nil 125 | } 126 | if isExist, _ := repository.IsExistDidDocLatest(ctx, invokedDidDoc.Controller.Did); !isExist { 127 | return GetContractError(DIDDOC_PROVIDER_INVALID, fmt.Errorf("cannot found provider")) 128 | } 129 | if err := verifyDidDocument(ctx, invokedDidDoc); err != nil { 130 | return GetContractError(DIDDOC_SIGNATURE_VERIFICATION_ERROR, err) 131 | } 132 | return nil 133 | } 134 | 135 | // verifyDidDocument 136 | /* 137 | The function verifies the signature of the DID document. 138 | 139 | * @param ctx The router context used for state management. 140 | * @param invokedDidDoc The invoked DID document to be verified. 141 | 142 | * @return An error if the verification fails, otherwise nil. 143 | */ 144 | func verifyDidDocument(ctx router.Context, invokedDidDoc *data.InvokedDidDoc) error { 145 | 146 | versionId, keyId, err := parsingKeyUrl(invokedDidDoc.Proof.VerificationMethod) 147 | if err != nil { 148 | return err 149 | } 150 | 151 | provider := invokedDidDoc.Controller.Did 152 | didDoc, _, err := getDidDocAndDocumentStatus(ctx, provider, versionId) 153 | if err != nil { 154 | return err 155 | } 156 | 157 | verificationMethod, err := didDoc.GetVerificationMethod(keyId) 158 | if err != nil { 159 | return err 160 | } 161 | 162 | compressedKey, err := utility.DecodeMultibase(verificationMethod.PublicKeyMultibase) 163 | if err != nil { 164 | return err 165 | } 166 | 167 | publicKey, err := utility.DecompressPublicKey(compressedKey) 168 | if err != nil { 169 | return err 170 | } 171 | signature, err := utility.DecodeMultibase(invokedDidDoc.Proof.ProofValue) 172 | if err != nil { 173 | return err 174 | } 175 | 176 | invokedDidDoc.Proof.ProofValue = "" 177 | documentDtoJson, _ := json.Marshal(invokedDidDoc) 178 | plainText := utility.SortJson(documentDtoJson) 179 | 180 | log.Printf("plain text : %s\n", plainText) 181 | if !utility.Verify(plainText, signature[1:], publicKey) { 182 | return fmt.Errorf("cannot verify signature") 183 | } 184 | 185 | return nil 186 | } 187 | 188 | // parsingKeyUrl 189 | /* 190 | The function parses the key URL to extract the version ID and key ID. 191 | 192 | * @param keyUrl The key URL to be parsed. 193 | 194 | * @return The extracted version ID. 195 | * @return The extracted key ID. 196 | * @return An error if parsing fails. 197 | */ 198 | func parsingKeyUrl(keyUrl data.DID_KEY_URL) (string, string, error) { 199 | versionSplit := strings.Split(string(keyUrl), "versionId=") 200 | if len(versionSplit) != 2 { 201 | return "", "", fmt.Errorf("invalid verificationMethod. missing versionId") 202 | } 203 | 204 | versionPart := versionSplit[1] 205 | 206 | keySplit := strings.Split(versionPart, "#") 207 | if len(keySplit) != 2 { 208 | return "", "", fmt.Errorf("invalid verificationMethod. missing keyId") 209 | } 210 | 211 | versionId := keySplit[0] 212 | keyId := keySplit[1] 213 | 214 | return versionId, keyId, nil 215 | } 216 | 217 | // convertFromMultiBaseToDocument 218 | /* 219 | The function converts a document hash from multibase format to a DID document. 220 | 221 | * @param documentHash The multibase-encoded document hash to be converted. 222 | 223 | * @return The DID document corresponding to the document hash. 224 | * @return An error if the conversion fails. 225 | */ 226 | func convertFromMultiBaseToDocument(documentHash data.Multibase) (*data.DidDoc, error) { 227 | documentByteData, err := utility.DecodeMultibase(documentHash) 228 | if err != nil { 229 | return nil, err 230 | } 231 | didDoc := new(data.DidDoc) 232 | json.Unmarshal(documentByteData, didDoc) 233 | if err := validator.New().Struct(didDoc); err != nil { 234 | return nil, err 235 | } 236 | return didDoc, nil 237 | 238 | } 239 | 240 | // saveOrUpdateDocument 241 | /* 242 | The function saves or updates the DID document and its status in the ledger. 243 | 244 | * @param ctx The router context used for state management. 245 | * @param didDoc The DID document to be saved or updated. 246 | * @param documentStatus The status of the DID document to be saved or updated. 247 | 248 | * @return An error if saving or updating fails, otherwise nil. 249 | */ 250 | func saveOrUpdateDocument(ctx router.Context, didDoc *data.DidDoc, documentStatus *data.DocumentStatus) error { 251 | 252 | savedDidDoc, savedDocumentStatus, err := getDidDocAndDocumentStatus(ctx, didDoc.Id, "") 253 | if err != nil && !strings.Contains(err.Error(), state.ErrKeyNotFound.Error()) { 254 | return err 255 | } 256 | 257 | if savedDidDoc == nil { 258 | return saveDidDocAndStatus(ctx, didDoc, documentStatus) 259 | } else { 260 | return updateDidDocAndStatus(ctx, didDoc, savedDidDoc, savedDocumentStatus) 261 | } 262 | } 263 | 264 | // saveDidDocAndStatus 265 | /* 266 | The function saves the DID document and its status into the ledger. 267 | 268 | * @param ctx The router context used for state management. 269 | * @param didDoc The DID document to be saved. 270 | * @param documentStatus The status of the DID document to be saved. 271 | 272 | * @return An error if saving fails, otherwise nil. 273 | */ 274 | func saveDidDocAndStatus(ctx router.Context, didDoc *data.DidDoc, documentStatus *data.DocumentStatus) error { 275 | if err := repository.InsertDidDocLatest(ctx, didDoc); err != nil { 276 | return err 277 | } 278 | return repository.InsertDocumentStatus(ctx, documentStatus) 279 | } 280 | 281 | // updateDidDocAndStatus 282 | /* 283 | The function updates the DID document and its status in the ledger. 284 | 285 | * @param ctx The router context used for state management. 286 | * @param didDoc The DID document to be updated. 287 | * @param savedDidDoc The previously saved DID document. 288 | * @param savedDocumentStatus The previously saved document status. 289 | 290 | * @return An error if updating fails, otherwise nil. 291 | */ 292 | func updateDidDocAndStatus(ctx router.Context, didDoc *data.DidDoc, savedDidDoc *data.DidDoc, savedDocumentStatus *data.DocumentStatus) error { 293 | if savedDidDoc.VersionId >= didDoc.VersionId { 294 | return GetContractError(DIDDOC_VERSIONID_INVAILD, fmt.Errorf("cannot update didDoc. saved didDoc version id : %s, new didDoc version id %s", savedDidDoc.VersionId, didDoc.VersionId)) 295 | } 296 | if err := repository.PutDidDocLatest(ctx, didDoc); err != nil { 297 | return err 298 | } 299 | if err := repository.InsertDidDocWithVersionId(ctx, data.MakeDidDocWithVersionId(savedDidDoc)); err != nil { 300 | return err 301 | } 302 | savedDocumentStatus.Version = didDoc.VersionId 303 | return repository.PutDocumentStatus(ctx, savedDocumentStatus) 304 | } 305 | 306 | // GetDidDocAndStatus 307 | /* 308 | The function retrieves the DID document and its status based on DID and version ID. 309 | 310 | * @param ctx The router context used for state management. 311 | * @param did The DID of the document. 312 | * @param versionId The version ID of the document (empty string to get the latest version). 313 | 314 | * @return The DID document and its status if found. 315 | * @return An error if retrieval fails or if there are issues during processing. 316 | */ 317 | func GetDidDocAndStatus(ctx router.Context, did, versionId string) (*data.DidDocAndStatus, error) { 318 | didDoc, documentStatus, err := getDidDocAndDocumentStatus(ctx, did, versionId) 319 | if err != nil { 320 | if strings.Contains(err.Error(), state.ErrKeyNotFound.Error()) { 321 | return nil, nil 322 | } 323 | return nil, err 324 | } 325 | return data.MakeDidDocAndStatus(didDoc, documentStatus.Status), nil 326 | } 327 | 328 | // getDidDocAndDocumentStatus 329 | /* 330 | The function retrieves the DID document and its status based on DID and version ID. 331 | 332 | * @param ctx The router context used for state management. 333 | * @param did The DID of the document. 334 | * @param versionId The version ID of the document (empty string to get the latest version). 335 | 336 | * @return The DID document and its status if found. 337 | * @return An error if retrieval fails. 338 | */ 339 | func getDidDocAndDocumentStatus(ctx router.Context, did, versionId string) (*data.DidDoc, *data.DocumentStatus, error) { 340 | var didDoc *data.DidDoc 341 | var err error 342 | 343 | documentStatus, err := repository.GetDocumentStatus(ctx, did) 344 | if err != nil { 345 | return nil, nil, err 346 | } 347 | 348 | if versionId == "" || versionId == documentStatus.Version { 349 | didDoc, err = repository.GetDidDocLatest(ctx, did) 350 | } else { 351 | didDoc, err = repository.GetDidDocWithVersionID(ctx, did, versionId) 352 | } 353 | return didDoc, documentStatus, err 354 | } 355 | 356 | // UpdateDidDocStatusRevocation 357 | /* 358 | The function updates the status of the DID document to revoked and sets the termination time. 359 | 360 | * @param ctx The router context used for state management. 361 | * @param did The DID of the document to be updated. 362 | * @param status The new status of the document. 363 | * @param terminatedTime The time when the document was terminated. 364 | 365 | * @return The updated DID document if successful. 366 | * @return An error if updating fails. 367 | */ 368 | func UpdateDidDocStatusRevocation(ctx router.Context, did string, status data.DIDDOC_STATUS, terminatedTime data.UTCDateTime) (*data.DidDoc, error) { 369 | didDoc, documentStatus, err := getDidDocAndDocumentStatus(ctx, did, "") 370 | if err != nil { 371 | return nil, err 372 | } 373 | if err := updateDocumentStatus(documentStatus, status, terminatedTime); err != nil { 374 | return nil, GetContractError(DIDDOC_STATUS_INVALID, err) 375 | } 376 | 377 | return didDoc, repository.PutDocumentStatus(ctx, documentStatus) 378 | } 379 | 380 | // UpdateDidDocStatusInService 381 | /* 382 | The function updates the status of the DID document to in-service. 383 | 384 | * @param ctx The router context used for state management. 385 | * @param did The DID of the document to be updated. 386 | * @param versionId The version ID of the document to be updated. 387 | * @param status The new status of the document. 388 | 389 | * @return The updated DID document if successful. 390 | * @return An error if updating fails. 391 | */ 392 | func UpdateDidDocStatusInService(ctx router.Context, did string, versionId string, status data.DIDDOC_STATUS) (*data.DidDoc, error) { 393 | didDoc, documentStatus, err := getDidDocAndDocumentStatus(ctx, did, versionId) 394 | if err != nil { 395 | return nil, err 396 | } 397 | if err := didDoc.SwitchStatus(status); err != nil { 398 | return nil, GetContractError(DIDDOC_STATUS_INVALID, err) 399 | } 400 | 401 | if documentStatus.Version == didDoc.VersionId { 402 | err = repository.PutDidDocLatest(ctx, didDoc) 403 | } else { 404 | err = repository.PutDidDocWithVersionId(ctx, data.MakeDidDocWithVersionId(didDoc)) 405 | } 406 | return didDoc, err 407 | } 408 | 409 | // updateDocumentStatus 410 | /* 411 | The function updates the document status based on the new status. 412 | 413 | * @param documentStatus The document status to be updated. 414 | * @param status The new status to set. 415 | * @param terminatedTime The time when the document was terminated (if applicable). 416 | 417 | * @return An error if updating fails, otherwise nil. 418 | */ 419 | func updateDocumentStatus(documentStatus *data.DocumentStatus, status data.DIDDOC_STATUS, terminatedTime data.UTCDateTime) error { 420 | switch status { 421 | case data.DOC_REVOKED: 422 | return documentStatus.Revoke() 423 | case data.DOC_TERMINATED: 424 | return documentStatus.Terminated(terminatedTime) 425 | default: 426 | return fmt.Errorf("unsupported status: %s", status) 427 | } 428 | } 429 | -------------------------------------------------------------------------------- /source/did-fabric-contract/go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= 4 | github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= 5 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= 6 | github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= 7 | github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= 8 | github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= 9 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= 10 | github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= 11 | github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 12 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= 13 | github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= 14 | github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 19 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 20 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 21 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 22 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 23 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 24 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 25 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 26 | github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 27 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 28 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 29 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 30 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 31 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 32 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 33 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 34 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 35 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 36 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 37 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 38 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 39 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 40 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 41 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 42 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 43 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 44 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 45 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= 46 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 47 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 48 | github.com/hyperledger-labs/cckit v1.0.5 h1:wEbPkoerAKWsiZ1bClT/ByfaRaI72dtZyJLIRLgsOmI= 49 | github.com/hyperledger-labs/cckit v1.0.5/go.mod h1:IXBUL/t8dE96BzYxT8gP8AhI9q6nbhv2nOkdHiiSgJY= 50 | github.com/hyperledger/fabric v1.4.0-rc1.0.20200930182727-344fda602252 h1:lQq/yygTbHWPfjFZ1VgINd1TJY7rOJ/zglcl9nE/s9Q= 51 | github.com/hyperledger/fabric v1.4.0-rc1.0.20200930182727-344fda602252/go.mod h1:+kicKDn5xa88tOpOY/o6/7iB/RD7oOs2INzwVg2ARmM= 52 | github.com/hyperledger/fabric-amcl v0.0.0-20200128223036-d1aa2665426a h1:HgdNn3UYz8PdcZrLEk0IsSU4LRHp7yY2rgjIKcSiJaA= 53 | github.com/hyperledger/fabric-amcl v0.0.0-20200128223036-d1aa2665426a/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= 54 | github.com/hyperledger/fabric-chaincode-go v0.0.0-20240704073638-9fb89180dc17 h1:SCsBjYLaoHCuyN6D3AAEX+YjBEnXn7MVpxn3rNX5gu4= 55 | github.com/hyperledger/fabric-chaincode-go v0.0.0-20240704073638-9fb89180dc17/go.mod h1:6R5/nmBVrNVvk76xqH30j/ecqphXD3zS6gCeYPKK4nk= 56 | github.com/hyperledger/fabric-protos-go v0.3.3 h1:0nssqz8QWJNVNBVQz+IIfAd2j1ku7QPKFSM/1anKizI= 57 | github.com/hyperledger/fabric-protos-go v0.3.3/go.mod h1:BPXse9gIOQwyAePQrwQVUcc44bTW4bB5V3tujuvyArk= 58 | github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 59 | github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= 60 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 61 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 62 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 63 | github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= 64 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 65 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 66 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 67 | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= 68 | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= 69 | github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= 70 | github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= 71 | github.com/mwitkow/go-proto-validators v0.3.2 h1:qRlmpTzm2pstMKKzTdvwPCF5QfBNURSlAgN/R+qbKos= 72 | github.com/mwitkow/go-proto-validators v0.3.2/go.mod h1:ej0Qp0qMgHN/KtDyUt+Q1/tA7a5VarXUOUxD+oeD30w= 73 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 74 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= 75 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 76 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 77 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 78 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 79 | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= 80 | github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= 81 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 82 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 83 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 84 | github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= 85 | github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= 86 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 87 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 88 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 89 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 90 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 91 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 92 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 93 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 94 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 95 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 96 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 97 | github.com/sykesm/zap-logfmt v0.0.3 h1:3Wrhf7+I9JEUD8B6KPtDAr9j2jrS0/EPLy7GCE1t/+U= 98 | github.com/sykesm/zap-logfmt v0.0.3/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= 99 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 100 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 101 | go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= 102 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 103 | go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= 104 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 105 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= 106 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 107 | go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= 108 | go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= 109 | golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 110 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 111 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 112 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 113 | golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 114 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 115 | golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= 116 | golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= 117 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= 118 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 119 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 120 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 121 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 122 | golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= 123 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 124 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 125 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 126 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 127 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 128 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 129 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 130 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 131 | golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= 132 | golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 133 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 134 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 135 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 136 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 137 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 138 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 139 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 140 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 141 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 142 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 143 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 144 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 145 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 146 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 147 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 148 | golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= 149 | golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 150 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 151 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 152 | golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= 153 | golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 154 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 155 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 156 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 157 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 158 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 159 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 160 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 161 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 162 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 163 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 164 | golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= 165 | golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= 166 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 167 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 168 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 169 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 170 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= 171 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= 172 | google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= 173 | google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= 174 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 175 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 176 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 177 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 178 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 179 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 180 | google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= 181 | google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 182 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 183 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 184 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 185 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 186 | gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= 187 | gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= 188 | gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= 189 | gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= 190 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 191 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 192 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 193 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 194 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 195 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 196 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 197 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 198 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 199 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 200 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 201 | honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= 202 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 203 | --------------------------------------------------------------------------------